Merge remote-tracking branch 'upstream/master' into development
Conflicts: pygit2/decl.h test/test_repository.py
This commit is contained in:
		| @@ -26,6 +26,14 @@ Custom entries:: | ||||
|    >>> entry = pygit2.IndexEntry('README.md', blob_id, blob_filemode) | ||||
|    >>> repo.index.add(entry) | ||||
|  | ||||
| The index fulfills a dual role as the in-memory representation of the | ||||
| index file and data structure which represents a flat list of a | ||||
| tree. You can use it independently of the index file, e.g. | ||||
|  | ||||
|   >>> index = pygit2.Index() | ||||
|   >>> entry = pygit2.IndexEntry('README.md', blob_id, blob_filemode) | ||||
|   >>> index.add(entry) | ||||
|  | ||||
| The Index type | ||||
| ==================== | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,6 @@ | ||||
| from __future__ import absolute_import | ||||
|  | ||||
| # Low level API | ||||
| import _pygit2 | ||||
| from _pygit2 import * | ||||
|  | ||||
| # High level API | ||||
| @@ -42,14 +41,59 @@ from .config import Config | ||||
| from .errors import check_error | ||||
| from .ffi import ffi, C, to_str | ||||
|  | ||||
| def init_repository(path, bare=False): | ||||
| def init_repository(path, bare=False, | ||||
|                     flags=C.GIT_REPOSITORY_INIT_MKPATH, | ||||
|                     mode=0, | ||||
|                     workdir_path=None, | ||||
|                     description=None, | ||||
|                     template_path=None, | ||||
|                     initial_head=None, | ||||
|                     origin_url=None): | ||||
|     """ | ||||
|     Creates a new Git repository in the given *path*. | ||||
|  | ||||
|     If *bare* is True the repository will be bare, i.e. it will not have a | ||||
|     working copy. | ||||
|  | ||||
|     The *flags* may be a combination of: | ||||
|  | ||||
|     - GIT_REPOSITORY_INIT_BARE (overriden by the *bare* parameter) | ||||
|     - GIT_REPOSITORY_INIT_NO_REINIT | ||||
|     - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR | ||||
|     - GIT_REPOSITORY_INIT_MKDIR | ||||
|     - GIT_REPOSITORY_INIT_MKPATH (set by default) | ||||
|     - GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE | ||||
|  | ||||
|     The *mode* parameter may be any of GIT_REPOSITORY_SHARED_UMASK (default), | ||||
|     GIT_REPOSITORY_SHARED_GROUP or GIT_REPOSITORY_INIT_SHARED_ALL, or a custom | ||||
|     value. | ||||
|  | ||||
|     The *workdir_path*, *description*, *template_path*, *initial_head* and | ||||
|     *origin_url* are all strings. | ||||
|  | ||||
|     See libgit2's documentation on git_repository_init_ext for further details. | ||||
|     """ | ||||
|     _pygit2.init_repository(path, bare) | ||||
|     # Pre-process input parameters | ||||
|     if bare: | ||||
|         flags |= C.GIT_REPOSITORY_INIT_BARE | ||||
|  | ||||
|     # Options | ||||
|     options = ffi.new('git_repository_init_options *') | ||||
|     options.version = 1 | ||||
|     options.flags = flags | ||||
|     options.mode = mode | ||||
|     options.workdir_path = to_str(workdir_path) | ||||
|     options.description = to_str(description) | ||||
|     options.template_path = to_str(template_path) | ||||
|     options.initial_head = to_str(initial_head) | ||||
|     options.origin_url = to_str(origin_url) | ||||
|  | ||||
|     # Call | ||||
|     crepository = ffi.new('git_repository **') | ||||
|     err = C.git_repository_init_ext(crepository, to_str(path), options) | ||||
|     check_error(err) | ||||
|  | ||||
|     # Ok | ||||
|     return Repository(path) | ||||
|  | ||||
|  | ||||
| @@ -129,4 +173,27 @@ def clone_repository( | ||||
|  | ||||
|     return Repository(path) | ||||
|  | ||||
| def clone_into(repo, remote, branch=None): | ||||
|     """Clone into an empty repository from the specified remote | ||||
|  | ||||
|     :param Repository repo: The empty repository into which to clone | ||||
|  | ||||
|     :param Remote remote: The remote from which to clone | ||||
|  | ||||
|     :param str branch: Branch to checkout after the clone. Pass None | ||||
|      to use the remotes's default branch. | ||||
|  | ||||
|     This allows you specify arbitrary repository and remote configurations | ||||
|     before performing the clone step itself. E.g. you can replicate git-clone's | ||||
|     '--mirror' option by setting a refspec of '+refs/*:refs/*', 'core.mirror' to true | ||||
|     and calling this function. | ||||
|     """ | ||||
|  | ||||
|     err = C.git_clone_into(repo._repo, remote._remote, ffi.NULL, to_str(branch)) | ||||
|  | ||||
|     if remote._stored_exception: | ||||
|         raise remote._stored_exception | ||||
|  | ||||
|     check_error(err) | ||||
|  | ||||
| settings = Settings() | ||||
|   | ||||
							
								
								
									
										110
									
								
								pygit2/decl.h
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								pygit2/decl.h
									
									
									
									
									
								
							| @@ -5,8 +5,6 @@ typedef ... git_push; | ||||
| typedef ... git_cred; | ||||
| typedef ... git_diff_file; | ||||
| typedef ... git_tree; | ||||
| typedef ... git_config; | ||||
| typedef ... git_config_iterator; | ||||
| typedef ... git_signature; | ||||
|  | ||||
| #define GIT_OID_RAWSZ ... | ||||
| @@ -27,6 +25,7 @@ typedef struct git_strarray { | ||||
| 	size_t count; | ||||
| } git_strarray; | ||||
|  | ||||
|  | ||||
| typedef enum { | ||||
| 	GIT_OK = 0, | ||||
| 	GIT_ERROR = -1, | ||||
| @@ -78,11 +77,13 @@ typedef enum { | ||||
| 	GIT_DIRECTION_PUSH  = 1 | ||||
| } git_direction; | ||||
|  | ||||
|  | ||||
| typedef enum { | ||||
| 	GIT_CREDTYPE_USERPASS_PLAINTEXT = ..., | ||||
| 	GIT_CREDTYPE_SSH_KEY = ..., | ||||
| 	GIT_CREDTYPE_SSH_CUSTOM = ..., | ||||
| 	GIT_CREDTYPE_DEFAULT = ..., | ||||
| 	GIT_CREDTYPE_USERPASS_PLAINTEXT, | ||||
| 	GIT_CREDTYPE_SSH_KEY, | ||||
| 	GIT_CREDTYPE_SSH_CUSTOM, | ||||
| 	GIT_CREDTYPE_DEFAULT, | ||||
| 	... | ||||
| } git_credtype_t; | ||||
|  | ||||
| typedef int (*git_transport_message_cb)(const char *str, int len, void *data); | ||||
| @@ -108,10 +109,12 @@ 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); | ||||
| int git_remote_create(git_remote **out, | ||||
| 		git_repository *repo, | ||||
| 		const char *name, | ||||
| 		const char *url); | ||||
| int git_remote_create( | ||||
| 	git_remote **out, | ||||
| 	git_repository *repo, | ||||
| 	const char *name, | ||||
| 	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, | ||||
| @@ -143,9 +146,10 @@ int git_push_add_refspec(git_push *push, const char *refspec); | ||||
| int git_push_finish(git_push *push); | ||||
| int git_push_unpack_ok(git_push *push); | ||||
|  | ||||
| int git_push_status_foreach(git_push *push, | ||||
| 			int (*cb)(const char *ref, const char *msg, void *data), | ||||
| 			void *data); | ||||
| int git_push_status_foreach( | ||||
| 	git_push *push, | ||||
| 	int (*cb)(const char *ref, const char *msg, void *data), | ||||
| 	void *data); | ||||
|  | ||||
| int git_push_update_tips( | ||||
| 		git_push *push, | ||||
| @@ -176,6 +180,10 @@ int git_cred_ssh_key_new( | ||||
| 	const char *privatekey, | ||||
| 	const char *passphrase); | ||||
|  | ||||
| /* | ||||
|  * git_checkout | ||||
|  */ | ||||
|  | ||||
| typedef enum { ... } git_checkout_notify_t; | ||||
|  | ||||
| typedef int (*git_checkout_notify_cb)( | ||||
| @@ -227,6 +235,10 @@ typedef enum { | ||||
| 	GIT_CLONE_LOCAL_NO_LINKS, | ||||
| } git_clone_local_t; | ||||
|  | ||||
| /* | ||||
|  * git_clone | ||||
|  */ | ||||
|  | ||||
| typedef struct git_clone_options { | ||||
| 	unsigned int version; | ||||
|  | ||||
| @@ -242,10 +254,22 @@ typedef struct git_clone_options { | ||||
| } git_clone_options; | ||||
|  | ||||
| int git_clone(git_repository **out, | ||||
| 		const char *url, | ||||
| 		const char *local_path, | ||||
| 		const git_clone_options *options); | ||||
| 	const char *url, | ||||
| 	const char *local_path, | ||||
| 	const git_clone_options *options); | ||||
|  | ||||
| int git_clone_into( | ||||
| 	git_repository *repo, | ||||
| 	git_remote *remote, | ||||
| 	const git_checkout_options *co_opts, | ||||
| 	const char *branch); | ||||
|  | ||||
| /* | ||||
|  * git_config | ||||
|  */ | ||||
|  | ||||
| typedef ... git_config; | ||||
| typedef ... git_config_iterator; | ||||
|  | ||||
| typedef enum { | ||||
| 	GIT_CONFIG_LEVEL_SYSTEM = 1, | ||||
| @@ -284,8 +308,17 @@ int git_config_iterator_new(git_config_iterator **out, const git_config *cfg); | ||||
| int git_config_next(git_config_entry **entry, git_config_iterator *iter); | ||||
| void git_config_iterator_free(git_config_iterator *iter); | ||||
|  | ||||
| int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp); | ||||
| int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value); | ||||
| int git_config_multivar_iterator_new( | ||||
| 	git_config_iterator **out, | ||||
| 	const git_config *cfg, | ||||
| 	const char *name, | ||||
| 	const char *regexp); | ||||
|  | ||||
| int git_config_set_multivar( | ||||
| 	git_config *cfg, | ||||
| 	const char *name, | ||||
| 	const char *regexp, | ||||
| 	const char *value); | ||||
|  | ||||
| int git_config_new(git_config **out); | ||||
| int git_config_snapshot(git_config **out, git_config *config); | ||||
| @@ -293,3 +326,44 @@ int git_config_open_ondisk(git_config **out, const char *path); | ||||
| 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 | ||||
|  */ | ||||
| typedef enum { | ||||
| 	GIT_REPOSITORY_INIT_BARE, | ||||
| 	GIT_REPOSITORY_INIT_NO_REINIT, | ||||
| 	GIT_REPOSITORY_INIT_NO_DOTGIT_DIR, | ||||
| 	GIT_REPOSITORY_INIT_MKDIR, | ||||
| 	GIT_REPOSITORY_INIT_MKPATH, | ||||
| 	GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE, | ||||
| 	... | ||||
| } git_repository_init_flag_t; | ||||
|  | ||||
| typedef enum { | ||||
| 	GIT_REPOSITORY_INIT_SHARED_UMASK, | ||||
| 	GIT_REPOSITORY_INIT_SHARED_GROUP, | ||||
| 	GIT_REPOSITORY_INIT_SHARED_ALL, | ||||
| 	... | ||||
| } git_repository_init_mode_t; | ||||
|  | ||||
| typedef struct { | ||||
| 	unsigned int version; | ||||
| 	uint32_t    flags; | ||||
| 	uint32_t    mode; | ||||
| 	const char *workdir_path; | ||||
| 	const char *description; | ||||
| 	const char *template_path; | ||||
| 	const char *initial_head; | ||||
| 	const char *origin_url; | ||||
| } git_repository_init_options; | ||||
|  | ||||
| int git_repository_init( | ||||
| 	git_repository **out, | ||||
| 	const char *path, | ||||
| 	unsigned is_bare); | ||||
|  | ||||
| int git_repository_init_ext( | ||||
| 	git_repository **out, | ||||
| 	const char *repo_path, | ||||
| 	git_repository_init_options *opts); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ import sys | ||||
|  | ||||
| if major_version < 3: | ||||
|     def to_str(s, encoding='utf-8', errors='strict'): | ||||
|         if s == ffi.NULL or s == None: | ||||
|         if s == ffi.NULL or s is None: | ||||
|             return ffi.NULL | ||||
|  | ||||
|         if isinstance(s, unicode): | ||||
| @@ -48,7 +48,7 @@ if major_version < 3: | ||||
|         return s | ||||
| else: | ||||
|     def to_str(s, encoding='utf-8', errors='strict'): | ||||
|         if s == ffi.NULL or s == None: | ||||
|         if s == ffi.NULL or s is None: | ||||
|             return ffi.NULL | ||||
|  | ||||
|         if isinstance(s, bytes): | ||||
| @@ -108,7 +108,7 @@ dir_path = path.dirname(path.abspath(inspect.getfile(inspect.currentframe()))) | ||||
|  | ||||
| decl_path = path.join(dir_path, 'decl.h') | ||||
| with codecs.open(decl_path, 'r', 'utf-8') as header: | ||||
|         ffi.cdef(header.read()) | ||||
|     ffi.cdef(header.read()) | ||||
|  | ||||
| # if LIBGIT2 exists, set build and link against that version | ||||
| libgit2_path = getenv('LIBGIT2') | ||||
| @@ -118,4 +118,5 @@ if libgit2_path: | ||||
|     include_dirs = [path.join(libgit2_path, 'include')] | ||||
|     library_dirs = [path.join(libgit2_path, 'lib')] | ||||
|  | ||||
| C = ffi.verify("#include <git2.h>", libraries=["git2"], include_dirs=include_dirs, library_dirs=library_dirs) | ||||
| C = ffi.verify("#include <git2.h>", libraries=["git2"], | ||||
|                include_dirs=include_dirs, library_dirs=library_dirs) | ||||
|   | ||||
							
								
								
									
										43
									
								
								src/index.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/index.c
									
									
									
									
									
								
							| @@ -45,7 +45,7 @@ extern PyTypeObject RepositoryType; | ||||
| int | ||||
| Index_init(Index *self, PyObject *args, PyObject *kwds) | ||||
| { | ||||
|     char *path; | ||||
|     char *path = NULL; | ||||
|     int err; | ||||
|  | ||||
|     if (kwds && PyDict_Size(kwds) > 0) { | ||||
| @@ -53,9 +53,10 @@ Index_init(Index *self, PyObject *args, PyObject *kwds) | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     if (!PyArg_ParseTuple(args, "s", &path)) | ||||
|     if (!PyArg_ParseTuple(args, "|s", &path)) | ||||
|         return -1; | ||||
|  | ||||
|     self->repo = NULL; | ||||
|     err = git_index_open(&self->index, path); | ||||
|     if (err < 0) { | ||||
|         Error_set_str(err, path); | ||||
| @@ -425,26 +426,46 @@ Index_remove(Index *self, PyObject *args) | ||||
| PyDoc_STRVAR(Index_read_tree__doc__, | ||||
|   "read_tree(tree)\n" | ||||
|   "\n" | ||||
|   "Update the index file from the tree identified by the given oid."); | ||||
|   "Update the index file from the specified tree. The tree can be a Tree object or an Oid.\n" | ||||
|   "Using an Oid is only possible if this index is associated with a repository"); | ||||
|  | ||||
| PyObject * | ||||
| Index_read_tree(Index *self, PyObject *value) | ||||
| { | ||||
|     git_oid oid; | ||||
|     git_tree *tree; | ||||
|     int err; | ||||
|     git_tree *tree = NULL; | ||||
|     int err, need_free = 0; | ||||
|     size_t len; | ||||
|  | ||||
|     len = py_oid_to_git_oid(value, &oid); | ||||
|     if (len == 0) | ||||
|         return NULL; | ||||
|     if (len == 0) { | ||||
|         Tree *py_tree; | ||||
|         if (!PyObject_TypeCheck(value, &TreeType)) { | ||||
|             return NULL; | ||||
|         } | ||||
|  | ||||
|     err = git_tree_lookup_prefix(&tree, self->repo->repo, &oid, len); | ||||
|     if (err < 0) | ||||
|         return Error_set(err); | ||||
|         PyErr_Clear(); | ||||
|         py_tree = (Tree *) value; | ||||
|         tree = py_tree->tree; | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * if the user passed in an id but we're not associated with a | ||||
|      * repo, we can't do anything | ||||
|      */ | ||||
|     if (tree == NULL && self->repo == NULL) { | ||||
|         PyErr_SetString(PyExc_TypeError, "id given but no associated repository"); | ||||
|         return NULL; | ||||
|     } else if (tree == NULL) { | ||||
|         need_free = 1; | ||||
|         err = git_tree_lookup_prefix(&tree, self->repo->repo, &oid, len); | ||||
|         if (err < 0) | ||||
|             return Error_set(err); | ||||
|     } | ||||
|  | ||||
|     err = git_index_read_tree(self->index, tree); | ||||
|     git_tree_free(tree); | ||||
|     if (need_free) | ||||
|         git_tree_free(tree); | ||||
|     if (err < 0) | ||||
|         return Error_set(err); | ||||
|  | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/pygit2.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/pygit2.c
									
									
									
									
									
								
							| @@ -71,37 +71,6 @@ extern PyTypeObject BlameHunkType; | ||||
|  | ||||
|  | ||||
|  | ||||
| PyDoc_STRVAR(init_repository__doc__, | ||||
|     "init_repository(path, bare)\n" | ||||
|     "\n" | ||||
|     "Creates a new Git repository in the given path.\n" | ||||
|     "\n" | ||||
|     "Arguments:\n" | ||||
|     "\n" | ||||
|     "path\n" | ||||
|     "  Path where to create the repository.\n" | ||||
|     "\n" | ||||
|     "bare\n" | ||||
|     "  Whether the repository will be bare or not.\n"); | ||||
|  | ||||
| PyObject * | ||||
| init_repository(PyObject *self, PyObject *args) { | ||||
|     git_repository *repo; | ||||
|     const char *path; | ||||
|     unsigned int bare; | ||||
|     int err; | ||||
|  | ||||
|     if (!PyArg_ParseTuple(args, "sI", &path, &bare)) | ||||
|         return NULL; | ||||
|  | ||||
|     err = git_repository_init(&repo, path, bare); | ||||
|     if (err < 0) | ||||
|         return Error_set_str(err, path); | ||||
|  | ||||
|     git_repository_free(repo); | ||||
|     Py_RETURN_NONE; | ||||
| }; | ||||
|  | ||||
| PyDoc_STRVAR(discover_repository__doc__, | ||||
|   "discover_repository(path[, across_fs[, ceiling_dirs]]) -> str\n" | ||||
|   "\n" | ||||
| @@ -179,7 +148,6 @@ hash(PyObject *self, PyObject *args) | ||||
|  | ||||
|  | ||||
| PyMethodDef module_methods[] = { | ||||
|     {"init_repository", init_repository, METH_VARARGS, init_repository__doc__}, | ||||
|     {"discover_repository", discover_repository, METH_VARARGS, | ||||
|      discover_repository__doc__}, | ||||
|     {"hashfile", hashfile, METH_VARARGS, hashfile__doc__}, | ||||
|   | ||||
| @@ -34,7 +34,7 @@ import unittest | ||||
| import tempfile | ||||
|  | ||||
| import pygit2 | ||||
| from pygit2 import Repository | ||||
| from pygit2 import Repository, Index | ||||
| from . import utils | ||||
|  | ||||
|  | ||||
| @@ -206,5 +206,19 @@ class IndexEntryTest(utils.RepoTestCase): | ||||
|         tree_id = index.write_tree() | ||||
|         self.assertEqual('60e769e57ae1d6a2ab75d8d253139e6260e1f912', str(tree_id)) | ||||
|  | ||||
| class StandaloneIndexTest(utils.RepoTestCase): | ||||
|  | ||||
|     def test_create_empty(self): | ||||
|         index = Index() | ||||
|  | ||||
|     def test_create_empty_read_tree_as_string(self): | ||||
|         index = Index() | ||||
|         # no repo associated, so we don't know where to read from | ||||
|         self.assertRaises(TypeError, index, 'read_tree', 'fd937514cb799514d4b81bb24c5fcfeb6472b245') | ||||
|  | ||||
|     def test_create_empty_read_tree(self): | ||||
|         index = Index() | ||||
|         index.read_tree(self.repo['fd937514cb799514d4b81bb24c5fcfeb6472b245']) | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
|   | ||||
| @@ -42,7 +42,7 @@ from os.path import join, realpath | ||||
| 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, discover_repository | ||||
| from pygit2 import init_repository, clone_repository, clone_into, discover_repository | ||||
| from pygit2 import Oid, Reference, hashfile | ||||
| import pygit2 | ||||
| from . import utils | ||||
| @@ -456,6 +456,13 @@ class CloneRepositoryTest(utils.NoRepoTestCase): | ||||
|         self.assertFalse(repo.is_empty) | ||||
|         self.assertEqual(repo.remotes[0].name, "custom_remote") | ||||
|  | ||||
|     def test_clone_into(self): | ||||
|         repo_path = "./test/data/testrepo.git/" | ||||
|         repo = init_repository(os.path.join(self._temp_dir, "clone-into")) | ||||
|         remote = repo.create_remote("origin", 'file://' + os.path.realpath(repo_path)) | ||||
|         clone_into(repo, remote) | ||||
|         self.assertTrue('refs/remotes/origin/master' in repo.listall_references()) | ||||
|  | ||||
|     def test_clone_with_credentials(self): | ||||
|         credentials = pygit2.UserPass("libgit2", "libgit2") | ||||
|         repo = clone_repository( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Carlos Martín Nieto
					Carlos Martín Nieto