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