Merge remote-tracking branch 'upstream/master' into development

Conflicts:
	pygit2/decl.h
	test/test_repository.py
This commit is contained in:
Carlos Martín Nieto
2014-06-07 21:38:07 +02:00
8 changed files with 230 additions and 70 deletions

View File

@@ -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
====================

View File

@@ -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()

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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__},

View File

@@ -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()

View File

@@ -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(