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