diff --git a/0001-Update-to-libgit2-v0.23.patch b/0001-Update-to-libgit2-v0.23.patch new file mode 100644 index 0000000..7ebc119 --- /dev/null +++ b/0001-Update-to-libgit2-v0.23.patch @@ -0,0 +1,1097 @@ +From 81520c9c626e092bc45f9fc8ba138eefa4d1beb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= +Date: Mon, 8 Jun 2015 12:19:01 +0200 +Subject: [PATCH] Update to libgit2 v0.23 + +--- + .travis.sh | 2 +- + pygit2/__init__.py | 8 +-- + pygit2/config.py | 43 ++++++++++----- + pygit2/decl.h | 129 +++++++++++++++++++++++++++++++-------------- + pygit2/remote.py | 144 ++++++++++++++++++--------------------------------- + pygit2/repository.py | 63 +++++++++++----------- + pygit2/utils.py | 5 ++ + src/branch.c | 2 +- + src/pygit2.c | 3 +- + src/reference.c | 22 +++----- + src/repository.c | 12 ++--- + src/types.h | 4 +- + test/test_merge.py | 2 +- + test/test_refs.py | 3 +- + test/test_remote.py | 65 ++++++----------------- + 15 files changed, 252 insertions(+), 255 deletions(-) + +diff --git a/pygit2/__init__.py b/pygit2/__init__.py +index d963bca..709adca 100644 +--- a/pygit2/__init__.py ++++ b/pygit2/__init__.py +@@ -278,12 +278,12 @@ def clone_repository( + + opts.bare = bare + if credentials: +- opts.remote_callbacks.credentials = _credentials_cb +- opts.remote_callbacks.payload = d_handle ++ opts.fetch_opts.callbacks.credentials = _credentials_cb ++ opts.fetch_opts.callbacks.payload = d_handle + + if certificate: +- opts.remote_callbacks.certificate_check = _certificate_cb +- opts.remote_callbacks.payload = d_handle ++ opts.fetch_opts.callbacks.certificate_check = _certificate_cb ++ opts.fetch_opts.callbacks.payload = d_handle + + err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts) + +diff --git a/pygit2/config.py b/pygit2/config.py +index 33cc6da..a01fdf6 100644 +--- a/pygit2/config.py ++++ b/pygit2/config.py +@@ -101,19 +101,19 @@ class Config(object): + def _get(self, key): + assert_string(key, "key") + +- cstr = ffi.new('char **') +- err = C.git_config_get_string(cstr, self._config, to_bytes(key)) ++ entry = ffi.new('git_config_entry **') ++ err = C.git_config_get_entry(entry, self._config, to_bytes(key)) + +- return err, cstr ++ return err, ConfigEntry._from_c(entry[0]) + +- def _get_string(self, key): +- err, cstr = self._get(key) ++ def _get_entry(self, key): ++ err, entry = self._get(key) + + if err == C.GIT_ENOTFOUND: + raise KeyError(key) + + check_error(err) +- return cstr[0] ++ return entry + + def __contains__(self, key): + err, cstr = self._get(key) +@@ -126,9 +126,9 @@ class Config(object): + return True + + def __getitem__(self, key): +- val = self._get_string(key) ++ entry = self._get_entry(key) + +- return ffi.string(val).decode('utf-8') ++ return ffi.string(entry.value).decode('utf-8') + + def __setitem__(self, key, value): + assert_string(key, "key") +@@ -192,9 +192,10 @@ class Config(object): + Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false', + 0, 'off' and 'no' + """ +- val = self._get_string(key) ++ ++ entry = self._get_entry(key) + res = ffi.new('int *') +- err = C.git_config_parse_bool(res, val) ++ err = C.git_config_parse_bool(res, entry.value) + check_error(err) + + return res[0] != 0 +@@ -206,9 +207,10 @@ class Config(object): + A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo', + 'mega' and 'giga' respectively. + """ +- val = self._get_string(key) ++ ++ entry = self._get_entry(key) + res = ffi.new('int64_t *') +- err = C.git_config_parse_int64(res, val) ++ err = C.git_config_parse_int64(res, entry.value) + check_error(err) + + return res[0] +@@ -283,3 +285,20 @@ class Config(object): + """Return a object representing the global configuration file. + """ + return Config._from_found_config(C.git_config_find_xdg) ++ ++class ConfigEntry(object): ++ """An entry in a configuation object ++ """ ++ ++ @classmethod ++ def _from_c(cls, ptr): ++ entry = cls.__new__(cls) ++ entry._entry = ptr ++ return entry ++ ++ def __del__(self): ++ C.git_config_entry_free(self._entry) ++ ++ @property ++ def value(self): ++ return self._entry.value +diff --git a/pygit2/decl.h b/pygit2/decl.h +index 2ea73f2..61afe33 100644 +--- a/pygit2/decl.h ++++ b/pygit2/decl.h +@@ -1,6 +1,7 @@ + typedef ... git_repository; + typedef ... git_submodule; + typedef ... git_remote; ++typedef ... git_transport; + typedef ... git_refspec; + typedef ... git_cred; + typedef ... git_object; +@@ -51,7 +52,7 @@ typedef enum { + GIT_EUNMERGED = -10, + GIT_ENONFASTFORWARD = -11, + GIT_EINVALIDSPEC = -12, +- GIT_EMERGECONFLICT = -13, ++ GIT_ECONFLICT = -13, + GIT_ELOCKED = -14, + + GIT_PASSTHROUGH = -30, +@@ -118,6 +119,7 @@ typedef enum { + } git_credtype_t; + + typedef enum git_cert_t { ++ GIT_CERT_NONE, + GIT_CERT_X509, + GIT_CERT_HOSTKEY_LIBSSH2, + } git_cert_t; +@@ -165,6 +167,16 @@ typedef int (*git_push_transfer_progress)( + size_t bytes, + void* payload); + ++typedef struct { ++ char *src_refname; ++ char *dst_refname; ++ git_oid src; ++ git_oid dst; ++} git_push_update; ++ ++typedef int (*git_push_negotiation)(const git_push_update **updates, size_t len, void *payload); ++typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param); ++ + struct git_remote_callbacks { + unsigned int version; + git_transport_message_cb sideband_progress; +@@ -173,19 +185,51 @@ struct git_remote_callbacks { + git_transport_certificate_check_cb certificate_check; + git_transfer_progress_cb transfer_progress; + int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data); +- git_packbuilder_progress pack_progress; ++ git_packbuilder_progress pack_progress; + git_push_transfer_progress push_transfer_progress; + int (*push_update_reference)(const char *refname, const char *status, void *data); ++ git_push_negotiation push_negotiation; ++ git_transport_cb transport; + void *payload; + }; + ++#define GIT_REMOTE_CALLBACKS_VERSION ... ++ + typedef struct git_remote_callbacks git_remote_callbacks; + + typedef struct { + unsigned int version; + unsigned int pb_parallelism; ++ git_remote_callbacks callbacks; + } git_push_options; + ++#define GIT_PUSH_OPTIONS_VERSION ... ++int git_push_init_options(git_push_options *opts, unsigned int version); ++ ++typedef enum { ++ GIT_FETCH_PRUNE_UNSPECIFIED, ++ GIT_FETCH_PRUNE, ++ GIT_FETCH_NO_PRUNE, ++} git_fetch_prune_t; ++ ++typedef enum { ++ GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED = 0, ++ GIT_REMOTE_DOWNLOAD_TAGS_AUTO, ++ GIT_REMOTE_DOWNLOAD_TAGS_NONE, ++ GIT_REMOTE_DOWNLOAD_TAGS_ALL, ++} git_remote_autotag_option_t; ++ ++typedef struct { ++ int version; ++ git_remote_callbacks callbacks; ++ git_fetch_prune_t prune; ++ int update_fetchhead; ++ git_remote_autotag_option_t download_tags; ++} git_fetch_options; ++ ++#define GIT_FETCH_OPTIONS_VERSION ... ++int git_fetch_init_options(git_fetch_options *opts, unsigned int version); ++ + int git_remote_list(git_strarray *out, git_repository *repo); + int git_remote_lookup(git_remote **out, git_repository *repo, const char *name); + int git_remote_create( +@@ -201,24 +245,20 @@ const char * git_remote_name(const git_remote *remote); + + int git_remote_rename(git_strarray *problems, git_repository *repo, const char *name, const char *new_name); + const char * git_remote_url(const git_remote *remote); +-int git_remote_set_url(git_remote *remote, const char* url); ++int git_remote_set_url(git_repository *repo, const char *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, const git_strarray *refspecs, const git_signature *signature, const char *reflog_message); +-int git_remote_push(git_remote *remote, git_strarray *refspecs, const git_push_options *opts, const git_signature *signature, const char *reflog_message); ++int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url); ++int git_remote_fetch(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts, const char *reflog_message); ++int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts); + 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); +-int git_remote_save(const git_remote *remote); +-int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks); ++int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec); ++int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec); + int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version); + size_t git_remote_refspec_count(git_remote *remote); + const git_refspec * git_remote_get_refspec(git_remote *remote, size_t n); + + int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote); +-int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array); + int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote); +-int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array); + + void git_remote_free(git_remote *remote); + +@@ -253,13 +293,12 @@ int git_cred_ssh_key_from_agent( + */ + + typedef enum { +- GIT_SUBMODULE_IGNORE_RESET = -1, ++ GIT_SUBMODULE_IGNORE_UNSPECIFIED = -1, + + GIT_SUBMODULE_IGNORE_NONE = 1, + GIT_SUBMODULE_IGNORE_UNTRACKED = 2, + GIT_SUBMODULE_IGNORE_DIRTY = 3, + GIT_SUBMODULE_IGNORE_ALL = 4, +- GIT_SUBMODULE_IGNORE_DEFAULT = 0 + } git_submodule_ignore_t; + + typedef enum { +@@ -348,32 +387,37 @@ typedef void (*git_checkout_progress_cb)( + size_t total_steps, + void *payload); + ++typedef struct { ++ size_t mkdir_calls; ++ size_t stat_calls; ++ size_t chmod_calls; ++} git_checkout_perfdata; ++ ++typedef void (*git_checkout_perfdata_cb)( ++ const git_checkout_perfdata *perfdata, ++ void *payload); ++ + typedef struct git_checkout_options { + unsigned int version; +- + unsigned int checkout_strategy; +- + int disable_filters; + unsigned int dir_mode; + unsigned int file_mode; + int file_open_flags; +- + unsigned int notify_flags; + git_checkout_notify_cb notify_cb; + void *notify_payload; +- + git_checkout_progress_cb progress_cb; + void *progress_payload; +- + git_strarray paths; +- + git_tree *baseline; +- ++ git_index *baseline_index; + const char *target_directory; +- + const char *ancestor_label; + const char *our_label; + const char *their_label; ++ git_checkout_perfdata_cb perfdata_cb; ++ void *perfdata_payload; + } git_checkout_options; + + int git_checkout_init_options(git_checkout_options *opts, unsigned int version); +@@ -408,11 +452,10 @@ typedef enum { + typedef struct git_clone_options { + unsigned int version; + git_checkout_options checkout_opts; +- git_remote_callbacks remote_callbacks; ++ git_fetch_options fetch_opts; + int bare; + git_clone_local_t local; + const char* checkout_branch; +- git_signature *signature; + git_repository_create_cb repository_cb; + void *repository_cb_payload; + git_remote_create_cb remote_cb; +@@ -443,16 +486,21 @@ typedef enum { + GIT_CONFIG_HIGHEST_LEVEL = -1, + } git_config_level_t; + +-typedef struct { ++typedef struct git_config_entry { + const char *name; + const char *value; + git_config_level_t level; ++ void (*free)(struct git_config_entry *entry); ++ void *payload; + } git_config_entry; + ++void git_config_entry_free(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_entry(git_config_entry **out, const git_config *cfg, const char *name); + int git_config_get_string(const char **out, const git_config *cfg, const char *name); + int git_config_set_string(git_config *cfg, const char *name, const char *value); + int git_config_set_bool(git_config *cfg, const char *name, int value); +@@ -535,8 +583,10 @@ int git_repository_init_ext( + const char *repo_path, + git_repository_init_options *opts); + +-int git_repository_set_head(git_repository *repo, const char *refname, const git_signature *signature, const char *log_message); +-int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish, const git_signature *signature, const char *log_message); ++int git_repository_set_head(git_repository *repo, const char *refname); ++int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish); ++int git_repository_ident(const char **name, const char **email, const git_repository *repo); ++int git_repository_set_ident(git_repository *repo, const char *name, const char *email); + int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream); + + /* +@@ -557,25 +607,25 @@ const char *git_submodule_branch(git_submodule *subm); + typedef int64_t git_time_t; + + typedef struct { +- git_time_t seconds; +- unsigned int nanoseconds; ++ int32_t seconds; ++ uint32_t nanoseconds; + } git_index_time; + + typedef struct git_index_entry { + git_index_time ctime; + git_index_time mtime; + +- unsigned int dev; +- unsigned int ino; +- unsigned int mode; +- unsigned int uid; +- unsigned int gid; +- git_off_t file_size; ++ uint32_t dev; ++ uint32_t ino; ++ uint32_t mode; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t file_size; + + git_oid id; + +- unsigned short flags; +- unsigned short flags_extended; ++ uint16_t flags; ++ uint16_t flags_extended; + + const char *path; + } git_index_entry; +@@ -664,13 +714,16 @@ typedef enum { + + typedef struct { + unsigned int version; +- git_merge_tree_flag_t flags; ++ git_merge_tree_flag_t tree_flags; + unsigned int rename_threshold; + unsigned int target_limit; + git_diff_similarity_metric *metric; + git_merge_file_favor_t file_favor; ++ unsigned int file_flags; + } git_merge_options; + ++#define GIT_MERGE_OPTIONS_VERSION 1 ++ + typedef struct { + unsigned int automergeable; + const char *path; +diff --git a/pygit2/remote.py b/pygit2/remote.py +index 8d2416b..7ec5bd4 100644 +--- a/pygit2/remote.py ++++ b/pygit2/remote.py +@@ -153,74 +153,44 @@ class Remote(object): + + return maybe_string(C.git_remote_url(self._remote)) + +- @url.setter +- def url(self, value): +- err = C.git_remote_set_url(self._remote, to_bytes(value)) +- check_error(err) +- + @property + def push_url(self): + """Push url of the remote""" + + return maybe_string(C.git_remote_pushurl(self._remote)) + +- @push_url.setter +- def push_url(self, value): +- err = C.git_remote_set_pushurl(self._remote, to_bytes(value)) +- check_error(err) +- + def save(self): + """Save a remote to its repository's configuration.""" + + err = C.git_remote_save(self._remote) + check_error(err) + +- def fetch(self, signature=None, message=None): ++ def fetch(self, refspecs=None, message=None): + """Perform a fetch against this remote. Returns a + object. + """ + +- # Get the default callbacks first +- defaultcallbacks = ffi.new('git_remote_callbacks *') +- err = C.git_remote_init_callbacks(defaultcallbacks, 1) +- check_error(err) ++ fetch_opts = ffi.new('git_fetch_options *') ++ err = C.git_fetch_init_options(fetch_opts, C.GIT_FETCH_OPTIONS_VERSION) + +- # Build custom callback structure +- callbacks = ffi.new('git_remote_callbacks *') +- callbacks.version = 1 +- 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 ++ fetch_opts.callbacks.sideband_progress = self._sideband_progress_cb ++ fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb ++ fetch_opts.callbacks.update_tips = self._update_tips_cb ++ fetch_opts.callbacks.credentials = self._credentials_cb + # We need to make sure that this handle stays alive + self._self_handle = ffi.new_handle(self) +- callbacks.payload = self._self_handle +- +- err = C.git_remote_set_callbacks(self._remote, callbacks) +- try: +- check_error(err) +- except: +- self._self_handle = None +- raise +- +- if signature: +- ptr = signature._pointer[:] +- else: +- ptr = ffi.NULL ++ fetch_opts.callbacks.payload = self._self_handle + + self._stored_exception = None + + try: +- err = C.git_remote_fetch(self._remote, ffi.NULL, ptr, to_bytes(message)) +- if self._stored_exception: +- raise self._stored_exception +- +- check_error(err) ++ with StrArray(refspecs) as arr: ++ err = C.git_remote_fetch(self._remote, arr, fetch_opts, to_bytes(message)) ++ if self._stored_exception: ++ raise self._stored_exception ++ check_error(err) + finally: +- # Even on error, clear stored callbacks and reset to default + self._self_handle = None +- err = C.git_remote_set_callbacks(self._remote, defaultcallbacks) +- check_error(err) + + return TransferProgress(C.git_remote_stats(self._remote)) + +@@ -245,12 +215,6 @@ class Remote(object): + + return strarray_to_strings(specs) + +- @fetch_refspecs.setter +- def fetch_refspecs(self, l): +- with StrArray(l) as arr: +- err = C.git_remote_set_fetch_refspecs(self._remote, arr) +- check_error(err) +- + @property + def push_refspecs(self): + """Refspecs that will be used for pushing""" +@@ -261,64 +225,28 @@ class Remote(object): + + return strarray_to_strings(specs) + +- @push_refspecs.setter +- def push_refspecs(self, l): +- with StrArray(l) as arr: +- err = C.git_remote_set_push_refspecs(self._remote, arr) +- check_error(err) +- +- def add_fetch(self, refspec): +- """Add a fetch refspec (str) to the remote.""" +- err = C.git_remote_add_fetch(self._remote, to_bytes(refspec)) +- check_error(err) +- +- def add_push(self, refspec): +- """Add a push refspec (str) to the remote.""" +- err = C.git_remote_add_push(self._remote, to_bytes(refspec)) +- check_error(err) +- +- def push(self, specs, signature=None, message=None): ++ def push(self, specs): + """Push the given refspec to the remote. Raises ``GitError`` on + protocol error or unpack failure. + + :param [str] specs: push refspecs to use +- :param Signature signature: signature to use when updating the tips (optional) +- :param str message: message to use when updating the tips (optional) + """ +- # Get the default callbacks first +- defaultcallbacks = ffi.new('git_remote_callbacks *') +- err = C.git_remote_init_callbacks(defaultcallbacks, 1) +- check_error(err) +- +- if signature: +- sig_cptr = ffi.new('git_signature **') +- ffi.buffer(sig_cptr)[:] = signature._pointer[:] +- sig_ptr = sig_cptr[0] +- else: +- sig_ptr = ffi.NULL ++ push_opts = ffi.new('git_push_options *') ++ err = C.git_push_init_options(push_opts, C.GIT_PUSH_OPTIONS_VERSION) + + # Build custom callback structure +- callbacks = ffi.new('git_remote_callbacks *') +- callbacks.version = 1 +- 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 +- callbacks.push_update_reference = self._push_update_reference_cb ++ push_opts.callbacks.sideband_progress = self._sideband_progress_cb ++ push_opts.callbacks.transfer_progress = self._transfer_progress_cb ++ push_opts.callbacks.update_tips = self._update_tips_cb ++ push_opts.callbacks.credentials = self._credentials_cb ++ push_opts.callbacks.push_update_reference = self._push_update_reference_cb + # We need to make sure that this handle stays alive + self._self_handle = ffi.new_handle(self) +- callbacks.payload = self._self_handle +- +- try: +- err = C.git_remote_set_callbacks(self._remote, callbacks) +- check_error(err) +- except: +- self._self_handle = None +- raise ++ push_opts.callbacks.payload = self._self_handle + + try: + with StrArray(specs) as refspecs: +- err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message)) ++ err = C.git_remote_push(self._remote, refspecs, ffi.NULL) + check_error(err) + finally: + self._self_handle = None +@@ -551,3 +479,29 @@ class RemoteCollection(object): + """ + err = C.git_remote_delete(self._repo._repo, to_bytes(name)) + check_error(err) ++ ++ def set_url(self, name, url): ++ """ Set the URL for a remote ++ """ ++ err = C.git_remote_set_url(self._repo._repo, to_bytes(name), to_bytes(url)) ++ check_error(err) ++ ++ def set_push_url(self, name, url): ++ """Set the push-URL for a remote ++ """ ++ err = C.git_remote_set_pushurl(self._repo._repo, to_bytes(name), to_bytes(url)) ++ check_error(err) ++ ++ def add_fetch(self, name, refspec): ++ """Add a fetch refspec (str) to the remote ++ """ ++ ++ err = C.git_remote_add_fetch(self._repo._repo, to_bytes(name), to_bytes(refspec)) ++ check_error(err) ++ ++ def add_push(self, name, refspec): ++ """Add a push refspec (str) to the remote ++ """ ++ ++ err = C.git_remote_add_push(self._repo._repo, to_bytes(name), to_bytes(refspec)) ++ check_error(err) +diff --git a/pygit2/repository.py b/pygit2/repository.py +index 64c08f9..b92a3a2 100644 +--- a/pygit2/repository.py ++++ b/pygit2/repository.py +@@ -40,7 +40,7 @@ else: + # Import from pygit2 + from _pygit2 import Repository as _Repository + from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN +-from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL ++from _pygit2 import GIT_CHECKOUT_SAFE, GIT_CHECKOUT_RECREATE_MISSING, GIT_DIFF_NORMAL + from _pygit2 import GIT_FILEMODE_LINK + from _pygit2 import Reference, Tree, Commit, Blob + +@@ -190,8 +190,8 @@ class Repository(_Repository): + # References we need to keep to strings and so forth + refs = [] + +- # pygit2's default is SAFE_CREATE +- copts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE ++ # pygit2's default is SAFE | RECREATE_MISSING ++ copts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING + # and go through the arguments to see what the user wanted + if strategy: + copts.checkout_strategy = strategy +@@ -235,7 +235,7 @@ class Repository(_Repository): + Checkout the given reference using the given strategy, and update + the HEAD. + The reference may be a reference name or a Reference object. +- The default strategy is GIT_CHECKOUT_SAFE_CREATE. ++ The default strategy is GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING. + + To checkout from the HEAD, just pass 'HEAD':: + +@@ -251,7 +251,7 @@ class Repository(_Repository): + the current branch will be switched to this one. + + :param int strategy: A ``GIT_CHECKOUT_`` value. The default is +- ``GIT_CHECKOUT_SAFE_CREATE``. ++ ``GIT_CHECKOUT_SAFE``. + + :param str directory: Alternative checkout path to workdir. + +@@ -281,50 +281,29 @@ class Repository(_Repository): + else: + from_ = head.target.hex + +- try: +- signature = self.default_signature +- except Exception: +- signature = None +- +- reflog_text = "checkout: moving from %s to %s" % (from_, reference) +- self.set_head(refname, signature, reflog_text) ++ self.set_head(refname) + + # + # Setting HEAD + # +- def set_head(self, target, signature=None, message=None): ++ def set_head(self, target): + """Set HEAD to point to the given target + + Arguments: + + target + The new target for HEAD. Can be a string or Oid (to detach) +- +- signature +- Signature to use for the reflog. If not provided, the repository's +- default will be used +- +- message +- Message to use for the reflog + """ + +- sig_ptr = ffi.new('git_signature **') +- if signature: +- ffi.buffer(sig_ptr)[:] = signature._pointer[:] +- +- message_ptr = ffi.NULL +- if message_ptr: +- message_ptr = to_bytes(message) +- + if isinstance(target, Oid): + oid = ffi.new('git_oid *') + ffi.buffer(oid)[:] = target.raw[:] +- err = C.git_repository_set_head_detached(self._repo, oid, sig_ptr[0], message_ptr) ++ err = C.git_repository_set_head_detached(self._repo, oid) + check_error(err) + return + + # if it's a string, then it's a reference name +- err = C.git_repository_set_head(self._repo, to_bytes(target), sig_ptr[0], message_ptr) ++ err = C.git_repository_set_head(self._repo, to_bytes(target)) + check_error(err) + + # +@@ -802,3 +781,27 @@ class Repository(_Repository): + return ffi.string(cvalue[0]).decode('utf-8') + + assert False, "the attribute value from libgit2 is invalid" ++ ++ # ++ # Identity for reference operations ++ # ++ @property ++ def ident(self): ++ cname = ffi.new('char **') ++ cemail = ffi.new('char **') ++ ++ err = C.git_repository_ident(cname, cemail, self._repo) ++ check_error(err) ++ ++ return (ffi.string(cname).decode('utf-8'), ffi.string(cemail).decode('utf-8')) ++ ++ def set_ident(self, name, email): ++ """Set the identity to be used for reference operations ++ ++ Updates to some references also append data to their ++ reflog. You can use this method to set what identity will be ++ used. If none is set, it will be read from the configuration. ++ """ ++ ++ err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email)) ++ check_error(err) +diff --git a/pygit2/utils.py b/pygit2/utils.py +index 89bc7ee..5b6a365 100644 +--- a/pygit2/utils.py ++++ b/pygit2/utils.py +@@ -61,6 +61,11 @@ class StrArray(object): + """ + + def __init__(self, l): ++ # Allow passing in None as lg2 typically considers them the same as empty ++ if l is None: ++ self.array = ffi.NULL ++ return ++ + if not isinstance(l, list): + raise TypeError("Value must be a list") + +diff --git a/src/branch.c b/src/branch.c +index 1793cea..d725ab1 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, NULL, NULL); ++ err = git_branch_move(&c_out, self->reference, c_name, force); + if (err == GIT_OK) + return wrap_branch(c_out, self->repo); + else +diff --git a/src/pygit2.c b/src/pygit2.c +index eedff26..12d365f 100644 +--- a/src/pygit2.c ++++ b/src/pygit2.c +@@ -273,10 +273,11 @@ moduleinit(PyObject* m) + ADD_CONSTANT_INT(m, GIT_STATUS_WT_MODIFIED) + ADD_CONSTANT_INT(m, GIT_STATUS_WT_DELETED) + ADD_CONSTANT_INT(m, GIT_STATUS_IGNORED) /* Flags for ignored files */ ++ ADD_CONSTANT_INT(m, GIT_STATUS_CONFLICTED) + /* Different checkout strategies */ + ADD_CONSTANT_INT(m, GIT_CHECKOUT_NONE) + ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE) +- ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE_CREATE) ++ ADD_CONSTANT_INT(m, GIT_CHECKOUT_RECREATE_MISSING) + ADD_CONSTANT_INT(m, GIT_CHECKOUT_FORCE) + ADD_CONSTANT_INT(m, GIT_CHECKOUT_ALLOW_CONFLICTS) + ADD_CONSTANT_INT(m, GIT_CHECKOUT_REMOVE_UNTRACKED) +diff --git a/src/reference.c b/src/reference.c +index 4d8e56e..2a20cca 100644 +--- a/src/reference.c ++++ b/src/reference.c +@@ -163,7 +163,7 @@ Reference_rename(Reference *self, PyObject *py_name) + return NULL; + + /* Rename */ +- err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL, NULL); ++ err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL); + git_reference_free(self->reference); + free(c_name); + if (err < 0) +@@ -228,7 +228,7 @@ Reference_target__get__(Reference *self) + } + + PyDoc_STRVAR(Reference_set_target__doc__, +- "set_target(target, [signature, message])\n" ++ "set_target(target, [message])\n" + "\n" + "Set the target of this reference.\n" + "\n" +@@ -240,9 +240,6 @@ PyDoc_STRVAR(Reference_set_target__doc__, + "\n" + "target\n" + " The new target for this reference\n" +- "signature\n" +- " The signature to use for the reflog. If left out, the repository's\n" +- " default identity will be used.\n" + "message\n" + " Message to use for the reflog.\n"); + +@@ -253,28 +250,23 @@ Reference_set_target(Reference *self, PyObject *args, PyObject *kwds) + char *c_name; + int err; + git_reference *new_ref; +- const git_signature *sig = NULL; + PyObject *py_target = NULL; +- Signature *py_signature = NULL; + const char *message = NULL; +- char *keywords[] = {"target", "signature", "message", NULL}; ++ char *keywords[] = {"target", "message", NULL}; + + CHECK_REFERENCE(self); + +- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O!s", keywords, +- &py_target, &SignatureType, &py_signature, &message)) ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", keywords, ++ &py_target, &message)) + return NULL; + +- if (py_signature) +- sig = py_signature->signature; +- + /* Case 1: Direct */ + if (GIT_REF_OID == git_reference_type(self->reference)) { + err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid); + if (err < 0) + goto error; + +- err = git_reference_set_target(&new_ref, self->reference, &oid, sig, message); ++ err = git_reference_set_target(&new_ref, self->reference, &oid, message); + if (err < 0) + goto error; + +@@ -288,7 +280,7 @@ Reference_set_target(Reference *self, PyObject *args, PyObject *kwds) + if (c_name == NULL) + return NULL; + +- err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, sig, message); ++ err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, message); + free(c_name); + if (err < 0) + goto error; +diff --git a/src/repository.c b/src/repository.c +index de93bb3..0195c01 100644 +--- a/src/repository.c ++++ b/src/repository.c +@@ -637,7 +637,7 @@ Repository_merge(Repository *self, PyObject *py_oid) + if (err < 0) + return Error_set(err); + +- checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; ++ checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + err = git_merge(self->repo, + (const git_annotated_commit **)&commit, 1, + &merge_opts, &checkout_opts); +@@ -677,7 +677,7 @@ Repository_cherrypick(Repository *self, PyObject *py_oid) + if (err < 0) + return Error_set(err); + +- cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; ++ cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + err = git_cherrypick(self->repo, + commit, + (const git_cherrypick_options *)&cherrypick_opts); +@@ -989,7 +989,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, NULL, NULL); ++ err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force); + if (err < 0) + return Error_set(err); + +@@ -1194,7 +1194,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, NULL, NULL); ++ err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL); + if (err < 0) + return Error_set(err); + +@@ -1228,7 +1228,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, NULL, NULL); ++ c_target, force, NULL); + if (err < 0) + return Error_set(err); + +@@ -1513,7 +1513,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, NULL, NULL, NULL); ++ err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL); + git_object_free(target); + if (err < 0) + return Error_set_oid(err, &oid, len); +diff --git a/src/types.h b/src/types.h +index f82ad47..f3c1858 100644 +--- a/src/types.h ++++ b/src/types.h +@@ -32,8 +32,8 @@ + #include + #include + +-#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 22) +-#error You need a compatible libgit2 version (v0.22.x) ++#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 23) ++#error You need a compatible libgit2 version (v0.23.x) + #endif + + /* +diff --git a/test/test_merge.py b/test/test_merge.py +index 7719d6d..86d1eea 100644 +--- a/test/test_merge.py ++++ b/test/test_merge.py +@@ -82,7 +82,7 @@ class MergeTestBasic(utils.RepoTestCaseForMerging): + + self.repo.merge(branch_id) + self.assertTrue(self.repo.index.conflicts is not None) +- status = pygit2.GIT_STATUS_WT_NEW | pygit2.GIT_STATUS_INDEX_DELETED ++ status = pygit2.GIT_STATUS_CONFLICTED + # Asking twice to assure the reference counting is correct + self.assertEqual({'.gitignore': status}, self.repo.status()) + self.assertEqual({'.gitignore': status}, self.repo.status()) +diff --git a/test/test_refs.py b/test/test_refs.py +index 1e78eb5..0d362c7 100644 +--- a/test/test_refs.py ++++ b/test/test_refs.py +@@ -114,8 +114,9 @@ class ReferencesTest(utils.RepoTestCase): + reference = self.repo.lookup_reference('HEAD') + self.assertEqual(reference.target, 'refs/heads/master') + sig = Signature('foo', 'bar') ++ self.repo.set_ident('foo', 'bar') + msg = 'Hello log' +- reference.set_target('refs/heads/i18n', signature=sig, message=msg) ++ reference.set_target('refs/heads/i18n', message=msg) + self.assertEqual(reference.target, 'refs/heads/i18n') + self.assertEqual(list(reference.log())[0].message, msg) + self.assertEqualSignature(list(reference.log())[0].committer, sig) +diff --git a/test/test_remote.py b/test/test_remote.py +index 751cddc..c2e4f8f 100644 +--- a/test/test_remote.py ++++ b/test/test_remote.py +@@ -100,22 +100,23 @@ class RepositoryTest(utils.RepoTestCase): + + + def test_remote_set_url(self): +- remote = self.repo.remotes[0] +- ++ remote = self.repo.remotes["origin"] + self.assertEqual(REMOTE_URL, remote.url) ++ + new_url = 'git://github.com/cholin/pygit2.git' +- remote.url = new_url ++ self.repo.remotes.set_url("origin", new_url) ++ remote = self.repo.remotes["origin"] + self.assertEqual(new_url, remote.url) + +- self.assertRaisesAssign(ValueError, remote, 'url', '') ++ self.assertRaises(ValueError, self.repo.remotes.set_url, "origin", "") + +- remote.push_url = new_url ++ self.repo.remotes.set_push_url("origin", new_url) ++ remote = self.repo.remotes["origin"] + self.assertEqual(new_url, remote.push_url) +- self.assertRaisesAssign(ValueError, remote, 'push_url', '') +- ++ self.assertRaises(ValueError, self.repo.remotes.set_push_url, "origin", "") + + def test_refspec(self): +- remote = self.repo.remotes[0] ++ remote = self.repo.remotes["origin"] + + self.assertEqual(remote.refspec_count, 1) + refspec = remote.get_refspec(0) +@@ -140,34 +141,20 @@ class RepositoryTest(utils.RepoTestCase): + self.assertEqual(list, type(push_specs)) + self.assertEqual(0, len(push_specs)) + +- remote.fetch_refspecs = ['+refs/*:refs/remotes/*'] +- self.assertEqual('+refs/*:refs/remotes/*', remote.fetch_refspecs[0]) ++ self.repo.remotes.add_fetch("origin", '+refs/test/*:refs/test/remotes/*') ++ remote = self.repo.remotes["origin"] + + fetch_specs = remote.fetch_refspecs + self.assertEqual(list, type(fetch_specs)) +- self.assertEqual(1, len(fetch_specs)) +- self.assertEqual('+refs/*:refs/remotes/*', fetch_specs[0]) +- +- remote.fetch_refspecs = ['+refs/*:refs/remotes/*', +- '+refs/test/*:refs/test/remotes/*'] +- self.assertEqual('+refs/*:refs/remotes/*', remote.fetch_refspecs[0]) +- self.assertEqual('+refs/test/*:refs/test/remotes/*', +- remote.fetch_refspecs[1]) ++ self.assertEqual(2, len(fetch_specs)) ++ self.assertEqual(['+refs/heads/*:refs/remotes/origin/*', '+refs/test/*:refs/test/remotes/*'], fetch_specs) + +- remote.push_refspecs = ['+refs/*:refs/remotes/*', +- '+refs/test/*:refs/test/remotes/*'] ++ self.repo.remotes.add_push("origin", '+refs/test/*:refs/test/remotes/*') + +- self.assertRaises(TypeError, setattr, remote, 'push_refspecs', +- '+refs/*:refs/*') +- self.assertRaises(TypeError, setattr, remote, 'fetch_refspecs', +- '+refs/*:refs/*') +- self.assertRaises(TypeError, setattr, remote, 'fetch_refspecs', +- ['+refs/*:refs/*', 5]) +- +- self.assertEqual('+refs/*:refs/remotes/*', remote.push_refspecs[0]) +- self.assertEqual('+refs/test/*:refs/test/remotes/*', +- remote.push_refspecs[1]) ++ self.assertRaises(TypeError, self.repo.remotes.add_fetch, ['+refs/*:refs/*', 5]) + ++ remote = self.repo.remotes["origin"] ++ self.assertEqual(['+refs/test/*:refs/test/remotes/*'], remote.push_refspecs) + + def test_remote_list(self): + self.assertEqual(1, len(self.repo.remotes)) +@@ -193,15 +180,6 @@ class RepositoryTest(utils.RepoTestCase): + remote = self.repo.remotes.create(name, url) + self.assertTrue(remote.name in [x.name for x in self.repo.remotes]) + +- +- def test_remote_save(self): +- remote = self.repo.remotes[0] +- remote.url = 'http://example.com/test.git' +- remote.save() +- +- self.assertEqual('http://example.com/test.git', +- self.repo.remotes[0].url) +- + @unittest.skipIf(__pypy__ is not None, "skip refcounts checks in pypy") + def test_remote_refcount(self): + start = sys.getrefcount(self.repo) +@@ -210,15 +188,6 @@ class RepositoryTest(utils.RepoTestCase): + end = sys.getrefcount(self.repo) + self.assertEqual(start, end) + +- def test_add_refspec(self): +- remote = self.repo.create_remote('test_add_refspec', REMOTE_URL) +- remote.add_push('refs/heads/*:refs/heads/test_refspec/*') +- self.assertEqual('refs/heads/*:refs/heads/test_refspec/*', +- remote.push_refspecs[0]) +- remote.add_fetch('+refs/heads/*:refs/remotes/test_refspec/*') +- self.assertEqual('+refs/heads/*:refs/remotes/test_refspec/*', +- remote.fetch_refspecs[1]) +- + def test_remote_callback_typecheck(self): + remote = self.repo.remotes[0] + remote.progress = 5 +-- +2.5.0 + diff --git a/python-pygit2.spec b/python-pygit2.spec index 9d9341d..699f19f 100644 --- a/python-pygit2.spec +++ b/python-pygit2.spec @@ -1,11 +1,12 @@ %global pkgname pygit2 +%global realver 0.22.1 Name: python-%{pkgname} -Version: 0.22.1 -Release: 2%{?dist} +Version: 0.23.0 +Release: 0.1%{?dist} Summary: Python 2.x bindings for libgit2 URL: http://www.pygit2.org -Source: http://pypi.python.org/packages/source/p/%{pkgname}/%{pkgname}-%{version}.tar.gz +Source: http://pypi.python.org/packages/source/p/%{pkgname}/%{pkgname}-%{realver}.tar.gz License: GPLv2 with linking exception BuildRequires: libgit2-devel BuildRequires: openssl-devel @@ -18,6 +19,9 @@ Requires: python-cffi Patch1: 0001-Remove-remote-calling-unit-tests.patch +# https://github.com/libgit2/pygit2/commit/81520c9c626e092bc45f9fc8ba138eefa4d1beb2 +Patch2: 0001-Update-to-libgit2-v0.23.patch + %description pygit2 is a set of Python bindings to the libgit2 library, which implements the core of Git. Pygit2 works with Python 2.7, 3.1, 3.2, 3.3, 3.4 and pypy. @@ -48,7 +52,9 @@ Documentation for %{name}. %prep -%setup -qn %{pkgname}-%{version} +%setup -qn %{pkgname}-%{realver} + +%patch2 -p1 %patch1 -p1 @@ -85,7 +91,7 @@ popd %files %doc README.rst TODO.txt %license COPYING -%{python2_sitearch}/%{pkgname}-%{version}-py%{python2_version}.egg-info +%{python2_sitearch}/%{pkgname}-%{realver}-py%{python2_version}.egg-info %{python2_sitearch}/%{pkgname} %{python2_sitearch}/_%{pkgname}.so %{python2_sitearch}/%{pkgname}_cffi_*.so @@ -93,7 +99,7 @@ popd %files -n python3-%{pkgname} %doc README.rst TODO.txt %license COPYING -%{python3_sitearch}/%{pkgname}-%{version}-py%{python3_version}.egg-info +%{python3_sitearch}/%{pkgname}-%{realver}-py%{python3_version}.egg-info %{python3_sitearch}/%{pkgname} %{python3_sitearch}/_%{pkgname}.*.so %{python3_sitearch}/%{pkgname}_cffi_*.so @@ -103,6 +109,9 @@ popd %changelog +* Fri Jul 31 2015 Igor Gnatenko - 0.23.0-0.1 +- Cherry-pick patch for 0.23.0 support + * Fri Jul 31 2015 Zbigniew Jędrzejewski-Szmek - 0.22.1-2 - Rebuilt for libgit2-0.23.0 and libgit2-glib-0.23