
Intoduce and use py_str_to_git_oid_expand() to get a full OID from a short one the user may have passed. Repository_contains() has learnt to do it by itself as expanding an OID means asking the repository's ODB for the object anyway. The return values have been made consistent with other functions and py_str_to_git_oid() now returns an int and marks errors with a negative value.
3267 lines
103 KiB
C
3267 lines
103 KiB
C
/*
|
|
* Copyright 2010 Google, Inc.
|
|
* Copyright 2011 Itaapy
|
|
*
|
|
* This file is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License, version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* In addition to the permissions in the GNU General Public License,
|
|
* the authors give you unlimited permission to link the compiled
|
|
* version of this file into combinations with other programs,
|
|
* and to distribute those combinations without any restriction
|
|
* coming from the use of this file. (The General Public License
|
|
* restrictions do apply in other respects; for example, they cover
|
|
* modification of the file, and distribution when not linked into
|
|
* a combined executable.)
|
|
*
|
|
* This file is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#define PY_SSIZE_T_CLEAN
|
|
#include <Python.h>
|
|
#include <osdefs.h>
|
|
#include <git2.h>
|
|
|
|
/* Python 3 support */
|
|
#if PY_MAJOR_VERSION >= 3
|
|
#define PyInt_AsLong PyLong_AsLong
|
|
#define PyInt_Check PyLong_Check
|
|
#define PyInt_FromLong PyLong_FromLong
|
|
#define PyString_AS_STRING PyBytes_AS_STRING
|
|
#define PyString_AsString PyBytes_AsString
|
|
#define PyString_AsStringAndSize PyBytes_AsStringAndSize
|
|
#define PyString_Check PyBytes_Check
|
|
#define PyString_FromString PyBytes_FromString
|
|
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
|
|
#define PyString_Size PyBytes_Size
|
|
#endif
|
|
|
|
/* Utilities */
|
|
Py_LOCAL_INLINE(PyObject*)
|
|
to_unicode(const char *value, const char *encoding, const char *errors)
|
|
{
|
|
if (encoding == NULL) {
|
|
/* If the encoding is not explicit, it may not be UTF-8, so it
|
|
* is not safe to decode it strictly. This is rare in the
|
|
* wild, but does occur in old commits to git itself
|
|
* (e.g. c31820c2). */
|
|
encoding = "utf-8";
|
|
errors = "replace";
|
|
}
|
|
return PyUnicode_Decode(value, strlen(value), encoding, errors);
|
|
}
|
|
|
|
Py_LOCAL_INLINE(PyObject*)
|
|
to_bytes(const char * value)
|
|
{
|
|
return PyString_FromString(value);
|
|
}
|
|
|
|
#if PY_MAJOR_VERSION == 2
|
|
#define to_path(x) to_bytes(x)
|
|
#define to_encoding(x) to_bytes(x)
|
|
#else
|
|
#define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict")
|
|
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
|
|
#endif
|
|
|
|
#define CHECK_REFERENCE(self)\
|
|
if (self->reference == NULL) {\
|
|
PyErr_SetString(GitError, "deleted reference");\
|
|
return NULL;\
|
|
}
|
|
|
|
#define CHECK_REFERENCE_INT(self)\
|
|
if (self->reference == NULL) {\
|
|
PyErr_SetString(GitError, "deleted reference");\
|
|
return -1;\
|
|
}
|
|
|
|
/* Python objects */
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
git_repository *repo;
|
|
PyObject *index; /* It will be None for a bare repository */
|
|
} Repository;
|
|
|
|
/* The structs for some of the object subtypes are identical except for
|
|
* the type of their object pointers. */
|
|
#define OBJECT_STRUCT(_name, _ptr_type, _ptr_name) \
|
|
typedef struct {\
|
|
PyObject_HEAD\
|
|
Repository *repo;\
|
|
_ptr_type *_ptr_name;\
|
|
} _name;
|
|
|
|
OBJECT_STRUCT(Object, git_object, obj)
|
|
OBJECT_STRUCT(Commit, git_commit, commit)
|
|
OBJECT_STRUCT(Tree, git_tree, tree)
|
|
OBJECT_STRUCT(TreeBuilder, git_treebuilder, bld)
|
|
OBJECT_STRUCT(Blob, git_blob, blob)
|
|
OBJECT_STRUCT(Tag, git_tag, tag)
|
|
OBJECT_STRUCT(Index, git_index, index)
|
|
OBJECT_STRUCT(Walker, git_revwalk, walk)
|
|
OBJECT_STRUCT(TreeEntry, git_tree_entry, entry)
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
Tree *owner;
|
|
int i;
|
|
} TreeIter;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
git_index_entry *entry;
|
|
} IndexEntry;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
Index *owner;
|
|
int i;
|
|
} IndexIter;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
git_reference *reference;
|
|
} Reference;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
Object *obj;
|
|
const git_signature *signature;
|
|
const char *encoding;
|
|
} Signature;
|
|
|
|
static PyTypeObject RepositoryType;
|
|
static PyTypeObject ObjectType;
|
|
static PyTypeObject CommitType;
|
|
static PyTypeObject TreeType;
|
|
static PyTypeObject TreeBuilderType;
|
|
static PyTypeObject TreeEntryType;
|
|
static PyTypeObject TreeIterType;
|
|
static PyTypeObject BlobType;
|
|
static PyTypeObject TagType;
|
|
static PyTypeObject IndexType;
|
|
static PyTypeObject IndexEntryType;
|
|
static PyTypeObject IndexIterType;
|
|
static PyTypeObject WalkerType;
|
|
static PyTypeObject ReferenceType;
|
|
static PyTypeObject SignatureType;
|
|
|
|
static PyObject *GitError;
|
|
|
|
static PyObject *
|
|
Error_type(int err)
|
|
{
|
|
switch (err) {
|
|
case GIT_ENOTFOUND:
|
|
return PyExc_KeyError;
|
|
case GIT_EOSERR:
|
|
return PyExc_OSError;
|
|
case GIT_ENOTOID:
|
|
return PyExc_ValueError;
|
|
case GIT_ENOMEM:
|
|
return PyExc_MemoryError;
|
|
case GIT_EREVWALKOVER:
|
|
return PyExc_StopIteration;
|
|
default:
|
|
return GitError;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Python doesn't like it when the error string is NULL. Not giving
|
|
* back an error string could be a bug in the library
|
|
*/
|
|
static const char *
|
|
git_last_error(void)
|
|
{
|
|
const char *ret;
|
|
|
|
ret = git_lasterror();
|
|
|
|
return ret != NULL ? ret : "(No error information given)";
|
|
}
|
|
|
|
static PyObject *
|
|
Error_set(int err)
|
|
{
|
|
assert(err < 0);
|
|
|
|
if (err == GIT_EOSERR)
|
|
return PyErr_SetFromErrno(GitError);
|
|
|
|
PyErr_SetString(Error_type(err), git_last_error());
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *
|
|
Error_set_str(int err, const char *str)
|
|
{
|
|
if (err == GIT_ENOTFOUND) {
|
|
/* KeyError expects the arg to be the missing key. */
|
|
PyErr_SetString(PyExc_KeyError, str);
|
|
return NULL;
|
|
}
|
|
|
|
return PyErr_Format(Error_type(err), "%s: %s", str, git_last_error());
|
|
}
|
|
|
|
static PyObject *
|
|
Error_set_oid(int err, const git_oid *oid, size_t len)
|
|
{
|
|
char hex[GIT_OID_HEXSZ + 1];
|
|
|
|
git_oid_fmt(hex, oid);
|
|
hex[len] = '\0';
|
|
return Error_set_str(err, hex);
|
|
}
|
|
|
|
static PyObject *
|
|
lookup_object_prefix(Repository *repo, const git_oid *oid, size_t len,
|
|
git_otype type)
|
|
{
|
|
int err;
|
|
git_object *obj;
|
|
Object *py_obj = NULL;
|
|
|
|
err = git_object_lookup_prefix(&obj, repo->repo, oid,
|
|
(unsigned int)len, type);
|
|
if (err < 0)
|
|
return Error_set_oid(err, oid, len);
|
|
|
|
switch (git_object_type(obj)) {
|
|
case GIT_OBJ_COMMIT:
|
|
py_obj = PyObject_New(Object, &CommitType);
|
|
break;
|
|
case GIT_OBJ_TREE:
|
|
py_obj = PyObject_New(Object, &TreeType);
|
|
break;
|
|
case GIT_OBJ_BLOB:
|
|
py_obj = PyObject_New(Object, &BlobType);
|
|
break;
|
|
case GIT_OBJ_TAG:
|
|
py_obj = PyObject_New(Object, &TagType);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
if (py_obj) {
|
|
py_obj->obj = obj;
|
|
py_obj->repo = repo;
|
|
Py_INCREF(repo);
|
|
}
|
|
return (PyObject*)py_obj;
|
|
}
|
|
|
|
static PyObject *
|
|
lookup_object(Repository *repo, const git_oid *oid, git_otype type)
|
|
{
|
|
return lookup_object_prefix(repo, oid, GIT_OID_HEXSZ, type);
|
|
}
|
|
|
|
static git_otype
|
|
int_to_loose_object_type(int type_id)
|
|
{
|
|
switch((git_otype)type_id) {
|
|
case GIT_OBJ_COMMIT: return GIT_OBJ_COMMIT;
|
|
case GIT_OBJ_TREE: return GIT_OBJ_TREE;
|
|
case GIT_OBJ_BLOB: return GIT_OBJ_BLOB;
|
|
case GIT_OBJ_TAG: return GIT_OBJ_TAG;
|
|
default: return GIT_OBJ_BAD;
|
|
}
|
|
}
|
|
|
|
static PyObject *
|
|
wrap_reference(git_reference * c_reference)
|
|
{
|
|
Reference *py_reference=NULL;
|
|
|
|
py_reference = PyObject_New(Reference, &ReferenceType);
|
|
if (py_reference)
|
|
py_reference->reference = c_reference;
|
|
|
|
return (PyObject *)py_reference;
|
|
}
|
|
|
|
static int
|
|
py_str_to_git_oid(PyObject *py_str, git_oid *oid)
|
|
{
|
|
PyObject *py_hex;
|
|
char *hex_or_bin;
|
|
int err;
|
|
Py_ssize_t len;
|
|
|
|
/* Case 1: raw sha */
|
|
if (PyString_Check(py_str)) {
|
|
hex_or_bin = PyString_AsString(py_str);
|
|
if (hex_or_bin == NULL)
|
|
return -1;
|
|
git_oid_fromraw(oid, (const unsigned char*)hex_or_bin);
|
|
return GIT_OID_HEXSZ;
|
|
}
|
|
|
|
/* Case 2: hex sha */
|
|
if (PyUnicode_Check(py_str)) {
|
|
py_hex = PyUnicode_AsASCIIString(py_str);
|
|
if (py_hex == NULL)
|
|
return -1;
|
|
err = PyString_AsStringAndSize(py_hex, &hex_or_bin, &len);
|
|
Py_DECREF(py_hex);
|
|
if (err)
|
|
return -1;
|
|
err = git_oid_fromstrn(oid, hex_or_bin, len);
|
|
if (err < 0) {
|
|
PyErr_SetObject(Error_type(err), py_str);
|
|
return -1;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/* Type error */
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Git object id must be byte or a text string, not: %.200s",
|
|
Py_TYPE(py_str)->tp_name);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
py_str_to_git_oid_expand(git_repository *repo, PyObject *py_str, git_oid *oid)
|
|
{
|
|
int err;
|
|
int len;
|
|
git_odb *odb;
|
|
git_odb_object *obj;
|
|
|
|
len = py_str_to_git_oid(py_str, oid);
|
|
|
|
if (len == GIT_OID_HEXSZ || len < 0)
|
|
return len;
|
|
|
|
err = git_repository_odb(&odb, repo);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
err = git_odb_read_prefix(&obj, odb, oid, len);
|
|
if (err < 0) {
|
|
git_odb_free(odb);
|
|
Error_set(err);
|
|
return err;
|
|
}
|
|
|
|
git_oid_cpy(oid, git_odb_object_id(obj));
|
|
|
|
git_odb_object_free(obj);
|
|
git_odb_free(odb);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define git_oid_to_python(id) \
|
|
PyString_FromStringAndSize((const char*)id, GIT_OID_RAWSZ)
|
|
|
|
static PyObject *
|
|
git_oid_to_py_str(const git_oid *oid)
|
|
{
|
|
char hex[GIT_OID_HEXSZ];
|
|
|
|
git_oid_fmt(hex, oid);
|
|
return PyUnicode_DecodeASCII(hex, GIT_OID_HEXSZ, "strict");
|
|
}
|
|
|
|
char *
|
|
py_str_to_c_str(PyObject *value, const char *encoding)
|
|
{
|
|
char *c_str;
|
|
|
|
/* Case 1: byte string */
|
|
if (PyString_Check(value))
|
|
return PyString_AsString(value);
|
|
|
|
/* Case 2: text string */
|
|
if (PyUnicode_Check(value)) {
|
|
if (encoding == NULL)
|
|
value = PyUnicode_AsUTF8String(value);
|
|
else
|
|
value = PyUnicode_AsEncodedString(value, encoding, "strict");
|
|
if (value == NULL)
|
|
return NULL;
|
|
c_str = PyString_AsString(value);
|
|
Py_DECREF(value);
|
|
return c_str;
|
|
}
|
|
|
|
/* Type error */
|
|
PyErr_Format(PyExc_TypeError, "unexpected %.200s",
|
|
Py_TYPE(value)->tp_name);
|
|
return NULL;
|
|
}
|
|
|
|
#define py_path_to_c_str(py_path) \
|
|
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
|
|
|
|
|
static int
|
|
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
char *path;
|
|
int err;
|
|
|
|
if (kwds) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Repository takes no keyword arguments");
|
|
return -1;
|
|
}
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &path))
|
|
return -1;
|
|
|
|
err = git_repository_open(&self->repo, path);
|
|
if (err < 0) {
|
|
Error_set_str(err, path);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
Repository_dealloc(Repository *self)
|
|
{
|
|
PyObject_GC_UnTrack(self);
|
|
Py_XDECREF(self->index);
|
|
git_repository_free(self->repo);
|
|
PyObject_GC_Del(self);
|
|
}
|
|
|
|
static int
|
|
Repository_traverse(Repository *self, visitproc visit, void *arg)
|
|
{
|
|
Py_VISIT(self->index);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Repository_clear(Repository *self)
|
|
{
|
|
Py_CLEAR(self->index);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Repository_contains(Repository *self, PyObject *value)
|
|
{
|
|
git_oid oid;
|
|
git_odb *odb;
|
|
int err, len, exists;
|
|
|
|
len = py_str_to_git_oid(value, &oid);
|
|
if (len < 0)
|
|
return -1;
|
|
|
|
err = git_repository_odb(&odb, self->repo);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
if (len < GIT_OID_HEXSZ) {
|
|
git_odb_object *obj = NULL;
|
|
err = git_odb_read_prefix(&obj, odb, &oid, len);
|
|
if (err < 0 && err != GIT_ENOTFOUND) {
|
|
Error_set(err);
|
|
exists = -1;
|
|
} else {
|
|
exists = (err == 0);
|
|
if (obj)
|
|
git_odb_object_free(obj);
|
|
}
|
|
} else {
|
|
exists = git_odb_exists(odb, &oid);
|
|
}
|
|
|
|
git_odb_free(odb);
|
|
return exists;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_getitem(Repository *self, PyObject *value)
|
|
{
|
|
git_oid oid;
|
|
int len;
|
|
|
|
len = py_str_to_git_oid(value, &oid);
|
|
if (len < 0)
|
|
return NULL;
|
|
|
|
return lookup_object_prefix(self, &oid, len, GIT_OBJ_ANY);
|
|
}
|
|
|
|
static git_odb_object *
|
|
Repository_read_raw(git_repository *repo, const git_oid *oid, size_t len)
|
|
{
|
|
git_odb *odb;
|
|
git_odb_object *obj;
|
|
int err;
|
|
|
|
err = git_repository_odb(&odb, repo);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return NULL;
|
|
}
|
|
|
|
err = git_odb_read_prefix(&obj, odb, oid, (unsigned int)len);
|
|
git_odb_free(odb);
|
|
if (err < 0) {
|
|
Error_set_oid(err, oid, len);
|
|
return NULL;
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_read(Repository *self, PyObject *py_hex)
|
|
{
|
|
git_oid oid;
|
|
git_odb_object *obj;
|
|
int len;
|
|
PyObject* tuple;
|
|
|
|
len = py_str_to_git_oid(py_hex, &oid);
|
|
if (len < 0)
|
|
return NULL;
|
|
|
|
obj = Repository_read_raw(self->repo, &oid, len);
|
|
if (obj == NULL)
|
|
return NULL;
|
|
|
|
tuple = Py_BuildValue(
|
|
"(ns#)",
|
|
git_odb_object_type(obj),
|
|
git_odb_object_data(obj),
|
|
git_odb_object_size(obj));
|
|
|
|
git_odb_object_free(obj);
|
|
return tuple;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_write(Repository *self, PyObject *args)
|
|
{
|
|
int err;
|
|
git_oid oid;
|
|
git_odb *odb;
|
|
git_odb_stream* stream;
|
|
int type_id;
|
|
const char* buffer;
|
|
Py_ssize_t buflen;
|
|
git_otype type;
|
|
|
|
if (!PyArg_ParseTuple(args, "Is#", &type_id, &buffer, &buflen))
|
|
return NULL;
|
|
|
|
type = int_to_loose_object_type(type_id);
|
|
if (type == GIT_OBJ_BAD)
|
|
return PyErr_Format(PyExc_ValueError, "%d", type_id);
|
|
|
|
err = git_repository_odb(&odb, self->repo);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
err = git_odb_open_wstream(&stream, odb, buflen, type);
|
|
git_odb_free(odb);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
stream->write(stream, buffer, buflen);
|
|
err = stream->finalize_write(&oid, stream);
|
|
stream->free(stream);
|
|
return git_oid_to_python(oid.id);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_get_index(Repository *self, void *closure)
|
|
{
|
|
int err;
|
|
git_index *index;
|
|
Index *py_index;
|
|
|
|
assert(self->repo);
|
|
|
|
if (self->index == NULL) {
|
|
err = git_repository_index(&index, self->repo);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
py_index = PyObject_GC_New(Index, &IndexType);
|
|
if (!py_index) {
|
|
git_index_free(index);
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(self);
|
|
py_index->repo = self;
|
|
py_index->index = index;
|
|
PyObject_GC_Track(py_index);
|
|
self->index = (PyObject*)py_index;
|
|
}
|
|
|
|
Py_INCREF(self->index);
|
|
return self->index;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_get_path(Repository *self, void *closure)
|
|
{
|
|
return to_path(git_repository_path(self->repo));
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_get_workdir(Repository *self, void *closure)
|
|
{
|
|
const char *c_path;
|
|
|
|
c_path = git_repository_workdir(self->repo);
|
|
if (c_path == NULL)
|
|
Py_RETURN_NONE;
|
|
|
|
return to_path(c_path);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_walk(Repository *self, PyObject *args)
|
|
{
|
|
PyObject *value;
|
|
unsigned int sort;
|
|
int err;
|
|
git_oid oid;
|
|
git_revwalk *walk;
|
|
Walker *py_walker;
|
|
|
|
if (!PyArg_ParseTuple(args, "OI", &value, &sort))
|
|
return NULL;
|
|
|
|
err = git_revwalk_new(&walk, self->repo);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* Sort */
|
|
git_revwalk_sorting(walk, sort);
|
|
|
|
/* Push */
|
|
if (value != Py_None) {
|
|
err = py_str_to_git_oid_expand(self->repo, value, &oid);
|
|
if (err < 0) {
|
|
git_revwalk_free(walk);
|
|
return Error_set(err);
|
|
}
|
|
|
|
err = git_revwalk_push(walk, &oid);
|
|
if (err < 0) {
|
|
git_revwalk_free(walk);
|
|
return Error_set(err);
|
|
}
|
|
}
|
|
|
|
py_walker = PyObject_New(Walker, &WalkerType);
|
|
if (!py_walker) {
|
|
git_revwalk_free(walk);
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(self);
|
|
py_walker->repo = self;
|
|
py_walker->walk = walk;
|
|
return (PyObject*)py_walker;
|
|
}
|
|
|
|
static PyObject *
|
|
build_signature(Object *obj, const git_signature *signature,
|
|
const char *encoding)
|
|
{
|
|
Signature *py_signature;
|
|
|
|
py_signature = PyObject_New(Signature, &SignatureType);
|
|
if (py_signature) {
|
|
Py_INCREF(obj);
|
|
py_signature->obj = obj;
|
|
py_signature->signature = signature;
|
|
py_signature->encoding = encoding;
|
|
}
|
|
return (PyObject*)py_signature;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_create_commit(Repository *self, PyObject *args)
|
|
{
|
|
Signature *py_author, *py_committer;
|
|
PyObject *py_oid, *py_message, *py_parents, *py_parent;
|
|
PyObject *py_result = NULL;
|
|
char *message, *update_ref, *encoding = NULL;
|
|
git_oid oid;
|
|
git_tree *tree = NULL;
|
|
int parent_count;
|
|
git_commit **parents = NULL;
|
|
int err = 0, i = 0, len;
|
|
|
|
if (!PyArg_ParseTuple(args, "zO!O!OOO!|s",
|
|
&update_ref,
|
|
&SignatureType, &py_author,
|
|
&SignatureType, &py_committer,
|
|
&py_message,
|
|
&py_oid,
|
|
&PyList_Type, &py_parents,
|
|
&encoding))
|
|
return NULL;
|
|
|
|
len = py_str_to_git_oid(py_oid, &oid);
|
|
if (len < 0)
|
|
goto out;
|
|
|
|
message = py_str_to_c_str(py_message, encoding);
|
|
if (message == NULL)
|
|
goto out;
|
|
|
|
err = git_tree_lookup_prefix(&tree, self->repo, &oid, (unsigned int)len);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
goto out;
|
|
}
|
|
|
|
parent_count = (int)PyList_Size(py_parents);
|
|
parents = malloc(parent_count * sizeof(git_commit*));
|
|
if (parents == NULL) {
|
|
PyErr_SetNone(PyExc_MemoryError);
|
|
goto out;
|
|
}
|
|
for (; i < parent_count; i++) {
|
|
py_parent = PyList_GET_ITEM(py_parents, i);
|
|
len = py_str_to_git_oid(py_parent, &oid);
|
|
if (len < 0)
|
|
goto out;
|
|
if (git_commit_lookup_prefix(&parents[i], self->repo, &oid,
|
|
(unsigned int)len))
|
|
goto out;
|
|
}
|
|
|
|
err = git_commit_create(&oid, self->repo, update_ref,
|
|
py_author->signature, py_committer->signature,
|
|
encoding, message, tree, parent_count,
|
|
(const git_commit**)parents);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
goto out;
|
|
}
|
|
|
|
py_result = git_oid_to_python(oid.id);
|
|
|
|
out:
|
|
git_tree_free(tree);
|
|
while (i > 0) {
|
|
i--;
|
|
git_commit_free(parents[i]);
|
|
}
|
|
free(parents);
|
|
return py_result;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_create_tag(Repository *self, PyObject *args)
|
|
{
|
|
PyObject *py_oid;
|
|
Signature *py_tagger;
|
|
char *tag_name, *message;
|
|
git_oid oid;
|
|
git_object *target = NULL;
|
|
int err, target_type, len;
|
|
|
|
if (!PyArg_ParseTuple(args, "sOiO!s",
|
|
&tag_name,
|
|
&py_oid,
|
|
&target_type,
|
|
&SignatureType, &py_tagger,
|
|
&message))
|
|
return NULL;
|
|
|
|
len = py_str_to_git_oid(py_oid, &oid);
|
|
if (len < 0)
|
|
return NULL;
|
|
|
|
err = git_object_lookup_prefix(&target, self->repo, &oid,
|
|
(unsigned int)len, target_type);
|
|
err = err < 0 ? err : git_tag_create(&oid, self->repo, tag_name, target,
|
|
py_tagger->signature, message, 0);
|
|
git_object_free(target);
|
|
if (err < 0)
|
|
return Error_set_oid(err, &oid, len);
|
|
return git_oid_to_python(oid.id);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_listall_references(Repository *self, PyObject *args)
|
|
{
|
|
unsigned list_flags=GIT_REF_LISTALL;
|
|
git_strarray c_result;
|
|
PyObject *py_result, *py_string;
|
|
unsigned index;
|
|
int err;
|
|
|
|
/* 1- Get list_flags */
|
|
if (!PyArg_ParseTuple(args, "|I", &list_flags))
|
|
return NULL;
|
|
|
|
/* 2- Get the C result */
|
|
err = git_reference_listall(&c_result, self->repo, list_flags);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* 3- Create a new PyTuple */
|
|
py_result = PyTuple_New(c_result.count);
|
|
if (py_result == NULL)
|
|
goto out;
|
|
|
|
/* 4- Fill it */
|
|
for (index=0; index < c_result.count; index++) {
|
|
py_string = to_path((c_result.strings)[index]);
|
|
if (py_string == NULL) {
|
|
Py_CLEAR(py_result);
|
|
goto out;
|
|
}
|
|
PyTuple_SET_ITEM(py_result, index, py_string);
|
|
}
|
|
|
|
out:
|
|
git_strarray_free(&c_result);
|
|
return py_result;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_lookup_reference(Repository *self, PyObject *py_name)
|
|
{
|
|
git_reference *c_reference;
|
|
char *c_name;
|
|
int err;
|
|
|
|
/* 1- Get the C name */
|
|
c_name = py_path_to_c_str(py_name);
|
|
if (c_name == NULL)
|
|
return NULL;
|
|
|
|
/* 2- Lookup */
|
|
err = git_reference_lookup(&c_reference, self->repo, c_name);
|
|
if (err < 0)
|
|
return Error_set_str(err, c_name);
|
|
|
|
/* 3- Make an instance of Reference and return it */
|
|
return wrap_reference(c_reference);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_create_reference(Repository *self, PyObject *args)
|
|
{
|
|
PyObject *py_oid;
|
|
git_reference *c_reference;
|
|
char *c_name;
|
|
git_oid oid;
|
|
int err;
|
|
|
|
/* 1- Get the C variables */
|
|
if (!PyArg_ParseTuple(args, "sO", &c_name, &py_oid))
|
|
return NULL;
|
|
|
|
err = py_str_to_git_oid_expand(self->repo, py_oid, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* 2- Create the reference */
|
|
err = git_reference_create_oid(&c_reference, self->repo, c_name, &oid, 0);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* 3- Make an instance of Reference and return it */
|
|
return wrap_reference(c_reference);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_create_symbolic_reference(Repository *self, PyObject *args)
|
|
{
|
|
git_reference *c_reference;
|
|
char *c_name, *c_target;
|
|
int err;
|
|
|
|
/* 1- Get the C variables */
|
|
if (!PyArg_ParseTuple(args, "ss", &c_name, &c_target))
|
|
return NULL;
|
|
|
|
/* 2- Create the reference */
|
|
err = git_reference_create_symbolic(&c_reference, self->repo, c_name,
|
|
c_target, 0);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* 3- Make an instance of Reference and return it */
|
|
return wrap_reference(c_reference);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_packall_references(Repository *self, PyObject *args)
|
|
{
|
|
int err;
|
|
|
|
/* 1- Pack */
|
|
err = git_reference_packall(self->repo);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
/* 2- Return None */
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static int
|
|
read_status_cb(const char *path, unsigned int status_flags, void *payload)
|
|
{
|
|
/* This is the callback that will be called in git_status_foreach. It
|
|
* will be called for every path.*/
|
|
PyObject *flags;
|
|
|
|
flags = PyInt_FromLong((long) status_flags);
|
|
PyDict_SetItemString(payload, path, flags);
|
|
|
|
return GIT_SUCCESS;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_status(Repository *self, PyObject *args)
|
|
{
|
|
PyObject *payload_dict;
|
|
|
|
payload_dict = PyDict_New();
|
|
git_status_foreach(self->repo, read_status_cb, payload_dict);
|
|
|
|
return payload_dict;
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_status_file(Repository *self, PyObject *value)
|
|
{
|
|
char *path;
|
|
unsigned int status;
|
|
int err;
|
|
|
|
path = py_path_to_c_str(value);
|
|
if (!path)
|
|
return NULL;
|
|
|
|
err = git_status_file(&status, self->repo, path);
|
|
if (err < 0)
|
|
return Error_set_str(err, path);
|
|
|
|
return PyInt_FromLong(status);
|
|
}
|
|
|
|
static PyObject *
|
|
Repository_TreeBuilder(Repository *self, PyObject *args)
|
|
{
|
|
TreeBuilder *builder;
|
|
git_treebuilder *bld;
|
|
PyObject *py_src = NULL;
|
|
git_oid oid;
|
|
git_tree *tree = NULL;
|
|
int err;
|
|
|
|
if (!PyArg_ParseTuple(args, "|O", &py_src))
|
|
return NULL;
|
|
|
|
if (py_src) {
|
|
if (PyObject_TypeCheck(py_src, &TreeType)) {
|
|
Tree *py_tree = (Tree *)py_src;
|
|
if (py_tree->repo->repo != self->repo) {
|
|
return Error_set(GIT_EINVALIDARGS);
|
|
}
|
|
tree = py_tree->tree;
|
|
} else {
|
|
err = py_str_to_git_oid_expand(self->repo, py_src, &oid);
|
|
if (err < 0)
|
|
return NULL;
|
|
|
|
err = git_tree_lookup(&tree, self->repo, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
}
|
|
}
|
|
|
|
err = git_treebuilder_create(&bld, tree);
|
|
git_tree_free(tree);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
builder = PyObject_New(TreeBuilder, &TreeBuilderType);
|
|
if (builder) {
|
|
builder->repo = self;
|
|
builder->bld = bld;
|
|
Py_INCREF(self);
|
|
}
|
|
|
|
return (PyObject*)builder;
|
|
}
|
|
|
|
static PyMethodDef Repository_methods[] = {
|
|
{"create_commit", (PyCFunction)Repository_create_commit, METH_VARARGS,
|
|
"Create a new commit object, return its SHA."},
|
|
{"create_tag", (PyCFunction)Repository_create_tag, METH_VARARGS,
|
|
"Create a new tag object, return its SHA."},
|
|
{"walk", (PyCFunction)Repository_walk, METH_VARARGS,
|
|
"Generator that traverses the history starting from the given commit."},
|
|
{"read", (PyCFunction)Repository_read, METH_O,
|
|
"Read raw object data from the repository."},
|
|
{"write", (PyCFunction)Repository_write, METH_VARARGS,
|
|
"Write raw object data into the repository. First arg is the object\n"
|
|
"type, the second one a buffer with data. Return the object id (sha)\n"
|
|
"of the created object."},
|
|
{"listall_references", (PyCFunction)Repository_listall_references,
|
|
METH_VARARGS,
|
|
"Return a list with all the references in the repository."},
|
|
{"lookup_reference", (PyCFunction)Repository_lookup_reference, METH_O,
|
|
"Lookup a reference by its name in a repository."},
|
|
{"create_reference", (PyCFunction)Repository_create_reference,
|
|
METH_VARARGS,
|
|
"Create a new reference \"name\" that points to the object given by its "
|
|
"\"sha\"."},
|
|
{"create_symbolic_reference",
|
|
(PyCFunction)Repository_create_symbolic_reference, METH_VARARGS,
|
|
"Create a new symbolic reference \"name\" that points to the reference\n"
|
|
"\"target\"."},
|
|
{"packall_references", (PyCFunction)Repository_packall_references,
|
|
METH_NOARGS, "Pack all the loose references in the repository."},
|
|
{"status", (PyCFunction)Repository_status, METH_NOARGS, "Reads the "
|
|
"status of the repository and returns a dictionnary with file paths "
|
|
"as keys and status flags as values.\nSee pygit2.GIT_STATUS_*."},
|
|
{"status_file", (PyCFunction)Repository_status_file, METH_O,
|
|
"Returns the status of the given file path."},
|
|
{"TreeBuilder", (PyCFunction)Repository_TreeBuilder, METH_VARARGS,
|
|
"Create a TreeBuilder object for this repository."},
|
|
{NULL}
|
|
};
|
|
|
|
static PyGetSetDef Repository_getseters[] = {
|
|
{"index", (getter)Repository_get_index, NULL, "index file. ", NULL},
|
|
{"path", (getter)Repository_get_path, NULL,
|
|
"The normalized path to the git repository.", NULL},
|
|
{"workdir", (getter)Repository_get_workdir, NULL,
|
|
"The normalized path to the working directory of the repository. "
|
|
"If the repository is bare, None will be returned.", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PySequenceMethods Repository_as_sequence = {
|
|
0, /* sq_length */
|
|
0, /* sq_concat */
|
|
0, /* sq_repeat */
|
|
0, /* sq_item */
|
|
0, /* sq_slice */
|
|
0, /* sq_ass_item */
|
|
0, /* sq_ass_slice */
|
|
(objobjproc)Repository_contains, /* sq_contains */
|
|
};
|
|
|
|
static PyMappingMethods Repository_as_mapping = {
|
|
0, /* mp_length */
|
|
(binaryfunc)Repository_getitem, /* mp_subscript */
|
|
0, /* mp_ass_subscript */
|
|
};
|
|
|
|
static PyTypeObject RepositoryType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Repository", /* tp_name */
|
|
sizeof(Repository), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Repository_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
&Repository_as_sequence, /* tp_as_sequence */
|
|
&Repository_as_mapping, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT |
|
|
Py_TPFLAGS_BASETYPE |
|
|
Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
|
"Git repository", /* tp_doc */
|
|
(traverseproc)Repository_traverse, /* tp_traverse */
|
|
(inquiry)Repository_clear, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
Repository_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
Repository_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
(initproc)Repository_init, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
Object_dealloc(Object* self)
|
|
{
|
|
git_object_free(self->obj);
|
|
Py_XDECREF(self->repo);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
Object_get_oid(Object *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
oid = git_object_id(self->obj);
|
|
assert(oid);
|
|
|
|
return git_oid_to_python(oid->id);
|
|
}
|
|
|
|
static PyObject *
|
|
Object_get_hex(Object *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
oid = git_object_id(self->obj);
|
|
assert(oid);
|
|
|
|
return git_oid_to_py_str(oid);
|
|
}
|
|
|
|
static PyObject *
|
|
Object_get_type(Object *self)
|
|
{
|
|
return PyInt_FromLong(git_object_type(self->obj));
|
|
}
|
|
|
|
static PyObject *
|
|
Object_read_raw(Object *self)
|
|
{
|
|
const git_oid *oid;
|
|
git_odb_object *obj;
|
|
PyObject *aux;
|
|
|
|
oid = git_object_id(self->obj);
|
|
assert(oid);
|
|
|
|
obj = Repository_read_raw(self->repo->repo, oid, GIT_OID_HEXSZ);
|
|
if (obj == NULL)
|
|
return NULL;
|
|
|
|
aux = PyString_FromStringAndSize(
|
|
git_odb_object_data(obj),
|
|
git_odb_object_size(obj));
|
|
|
|
git_odb_object_free(obj);
|
|
return aux;
|
|
}
|
|
|
|
static PyGetSetDef Object_getseters[] = {
|
|
{"oid", (getter)Object_get_oid, NULL, "object id", NULL},
|
|
{"hex", (getter)Object_get_hex, NULL, "hex oid", NULL},
|
|
{"type", (getter)Object_get_type, NULL, "type number", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyMethodDef Object_methods[] = {
|
|
{"read_raw", (PyCFunction)Object_read_raw, METH_NOARGS,
|
|
"Read the raw contents of the object from the repo."},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject ObjectType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Object", /* tp_name */
|
|
sizeof(Object), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Object_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"Object objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
Object_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
Object_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static PyObject *
|
|
Commit_get_message_encoding(Commit *commit)
|
|
{
|
|
const char *encoding;
|
|
|
|
encoding = git_commit_message_encoding(commit->commit);
|
|
if (encoding == NULL)
|
|
Py_RETURN_NONE;
|
|
|
|
return to_encoding(encoding);
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_message(Commit *commit)
|
|
{
|
|
const char *message, *encoding;
|
|
|
|
message = git_commit_message(commit->commit);
|
|
encoding = git_commit_message_encoding(commit->commit);
|
|
return to_unicode(message, encoding, "strict");
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_raw_message(Commit *commit)
|
|
{
|
|
return PyString_FromString(git_commit_message(commit->commit));
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_commit_time(Commit *commit)
|
|
{
|
|
return PyLong_FromLong(git_commit_time(commit->commit));
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_commit_time_offset(Commit *commit)
|
|
{
|
|
return PyLong_FromLong(git_commit_time_offset(commit->commit));
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_committer(Commit *self)
|
|
{
|
|
const git_signature *signature;
|
|
const char *encoding;
|
|
|
|
signature = git_commit_committer(self->commit);
|
|
encoding = git_commit_message_encoding(self->commit);
|
|
|
|
return build_signature((Object*)self, signature, encoding);
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_author(Commit *self)
|
|
{
|
|
const git_signature *signature;
|
|
const char *encoding;
|
|
|
|
signature = git_commit_author(self->commit);
|
|
encoding = git_commit_message_encoding(self->commit);
|
|
|
|
return build_signature((Object*)self, signature, encoding);
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_tree(Commit *commit)
|
|
{
|
|
git_tree *tree;
|
|
Tree *py_tree;
|
|
int err;
|
|
|
|
err = git_commit_tree(&tree, commit->commit);
|
|
if (err == GIT_ENOTFOUND)
|
|
Py_RETURN_NONE;
|
|
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
py_tree = PyObject_New(Tree, &TreeType);
|
|
if (py_tree) {
|
|
Py_INCREF(commit->repo);
|
|
py_tree->repo = commit->repo;
|
|
py_tree->tree = (git_tree*)tree;
|
|
}
|
|
return (PyObject*)py_tree;
|
|
}
|
|
|
|
static PyObject *
|
|
Commit_get_parents(Commit *commit)
|
|
{
|
|
unsigned int i, parent_count;
|
|
const git_oid *parent_oid;
|
|
PyObject *obj;
|
|
PyObject *list;
|
|
|
|
parent_count = git_commit_parentcount(commit->commit);
|
|
list = PyList_New(parent_count);
|
|
if (!list)
|
|
return NULL;
|
|
|
|
for (i=0; i < parent_count; i++) {
|
|
parent_oid = git_commit_parent_oid(commit->commit, i);
|
|
if (parent_oid == NULL) {
|
|
Py_DECREF(list);
|
|
Error_set(GIT_ENOTFOUND);
|
|
return NULL;
|
|
}
|
|
obj = lookup_object(commit->repo, parent_oid, GIT_OBJ_COMMIT);
|
|
if (obj == NULL) {
|
|
Py_DECREF(list);
|
|
return NULL;
|
|
}
|
|
|
|
PyList_SET_ITEM(list, i, obj);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
static PyGetSetDef Commit_getseters[] = {
|
|
{"message_encoding", (getter)Commit_get_message_encoding, NULL,
|
|
"message encoding", NULL},
|
|
{"message", (getter)Commit_get_message, NULL, "message", NULL},
|
|
{"_message", (getter)Commit_get_raw_message, NULL, "message (bytes)", NULL},
|
|
{"commit_time", (getter)Commit_get_commit_time, NULL, "commit time",
|
|
NULL},
|
|
{"commit_time_offset", (getter)Commit_get_commit_time_offset, NULL,
|
|
"commit time offset", NULL},
|
|
{"committer", (getter)Commit_get_committer, NULL, "committer", NULL},
|
|
{"author", (getter)Commit_get_author, NULL, "author", NULL},
|
|
{"tree", (getter)Commit_get_tree, NULL, "tree object", NULL},
|
|
{"parents", (getter)Commit_get_parents, NULL, "parents of this commit",
|
|
NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject CommitType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Commit", /* tp_name */
|
|
sizeof(Commit), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"Commit objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
Commit_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
TreeEntry_dealloc(TreeEntry *self)
|
|
{
|
|
Py_XDECREF(self->repo);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
TreeEntry_get_attributes(TreeEntry *self)
|
|
{
|
|
return PyInt_FromLong(git_tree_entry_attributes(self->entry));
|
|
}
|
|
|
|
static PyObject *
|
|
TreeEntry_get_name(TreeEntry *self)
|
|
{
|
|
return to_path(git_tree_entry_name(self->entry));
|
|
}
|
|
|
|
static PyObject *
|
|
TreeEntry_get_oid(TreeEntry *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
oid = git_tree_entry_id(self->entry);
|
|
return git_oid_to_python(oid->id);
|
|
}
|
|
|
|
static PyObject *
|
|
TreeEntry_get_hex(TreeEntry *self)
|
|
{
|
|
return git_oid_to_py_str(git_tree_entry_id(self->entry));
|
|
}
|
|
|
|
static PyObject *
|
|
TreeEntry_to_object(TreeEntry *self)
|
|
{
|
|
const git_oid *entry_oid;
|
|
|
|
entry_oid = git_tree_entry_id(self->entry);
|
|
return lookup_object(self->repo, entry_oid, GIT_OBJ_ANY);
|
|
}
|
|
|
|
static PyGetSetDef TreeEntry_getseters[] = {
|
|
{"attributes", (getter)TreeEntry_get_attributes, NULL, "attributes", NULL},
|
|
{"name", (getter)TreeEntry_get_name, NULL, "name", NULL},
|
|
{"oid", (getter)TreeEntry_get_oid, NULL, "object id", NULL},
|
|
{"hex", (getter)TreeEntry_get_hex, NULL, "hex oid", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyMethodDef TreeEntry_methods[] = {
|
|
{"to_object", (PyCFunction)TreeEntry_to_object, METH_NOARGS,
|
|
"Look up the corresponding object in the repo."},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
static PyTypeObject TreeEntryType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.TreeEntry", /* tp_name */
|
|
sizeof(TreeEntry), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)TreeEntry_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"TreeEntry objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
TreeEntry_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
TreeEntry_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static Py_ssize_t
|
|
Tree_len(Tree *self)
|
|
{
|
|
assert(self->tree);
|
|
return (Py_ssize_t)git_tree_entrycount(self->tree);
|
|
}
|
|
|
|
static int
|
|
Tree_contains(Tree *self, PyObject *py_name)
|
|
{
|
|
char *name;
|
|
|
|
name = py_path_to_c_str(py_name);
|
|
if (name == NULL)
|
|
return -1;
|
|
|
|
return git_tree_entry_byname(self->tree, name) ? 1 : 0;
|
|
}
|
|
|
|
static TreeEntry *
|
|
wrap_tree_entry(const git_tree_entry *entry, Repository *repo)
|
|
{
|
|
TreeEntry *py_entry;
|
|
|
|
py_entry = PyObject_New(TreeEntry, &TreeEntryType);
|
|
if (py_entry) {
|
|
py_entry->entry = entry;
|
|
py_entry->repo = repo;
|
|
Py_INCREF(repo);
|
|
}
|
|
return py_entry;
|
|
}
|
|
|
|
static int
|
|
Tree_fix_index(Tree *self, PyObject *py_index)
|
|
{
|
|
long index;
|
|
size_t len;
|
|
long slen;
|
|
|
|
index = PyInt_AsLong(py_index);
|
|
if (PyErr_Occurred())
|
|
return -1;
|
|
|
|
len = git_tree_entrycount(self->tree);
|
|
slen = (long)len;
|
|
if (index >= slen) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return -1;
|
|
}
|
|
else if (index < -slen) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return -1;
|
|
}
|
|
|
|
/* This function is called via mp_subscript, which doesn't do negative
|
|
* index rewriting, so we have to do it manually. */
|
|
if (index < 0)
|
|
index = len + index;
|
|
return (int)index;
|
|
}
|
|
|
|
static PyObject *
|
|
Tree_iter(Tree *self)
|
|
{
|
|
TreeIter *iter;
|
|
|
|
iter = PyObject_New(TreeIter, &TreeIterType);
|
|
if (iter) {
|
|
Py_INCREF(self);
|
|
iter->owner = self;
|
|
iter->i = 0;
|
|
}
|
|
return (PyObject*)iter;
|
|
}
|
|
|
|
static TreeEntry *
|
|
Tree_getitem_by_index(Tree *self, PyObject *py_index)
|
|
{
|
|
int index;
|
|
const git_tree_entry *entry;
|
|
|
|
index = Tree_fix_index(self, py_index);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
entry = git_tree_entry_byindex(self->tree, index);
|
|
if (!entry) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return NULL;
|
|
}
|
|
return wrap_tree_entry(entry, self->repo);
|
|
}
|
|
|
|
static TreeEntry *
|
|
Tree_getitem(Tree *self, PyObject *value)
|
|
{
|
|
char *name;
|
|
const git_tree_entry *entry;
|
|
|
|
/* Case 1: integer */
|
|
if (PyInt_Check(value))
|
|
return Tree_getitem_by_index(self, value);
|
|
|
|
/* Case 2: byte or text string */
|
|
name = py_path_to_c_str(value);
|
|
if (name == NULL)
|
|
return NULL;
|
|
entry = git_tree_entry_byname(self->tree, name);
|
|
if (!entry) {
|
|
PyErr_SetObject(PyExc_KeyError, value);
|
|
return NULL;
|
|
}
|
|
return wrap_tree_entry(entry, self->repo);
|
|
}
|
|
|
|
static PySequenceMethods Tree_as_sequence = {
|
|
0, /* sq_length */
|
|
0, /* sq_concat */
|
|
0, /* sq_repeat */
|
|
0, /* sq_item */
|
|
0, /* sq_slice */
|
|
0, /* sq_ass_item */
|
|
0, /* sq_ass_slice */
|
|
(objobjproc)Tree_contains, /* sq_contains */
|
|
};
|
|
|
|
static PyMappingMethods Tree_as_mapping = {
|
|
(lenfunc)Tree_len, /* mp_length */
|
|
(binaryfunc)Tree_getitem, /* mp_subscript */
|
|
0, /* mp_ass_subscript */
|
|
};
|
|
|
|
static PyTypeObject TreeType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Tree", /* tp_name */
|
|
sizeof(Tree), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
&Tree_as_sequence, /* tp_as_sequence */
|
|
&Tree_as_mapping, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"Tree objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
(getiterfunc)Tree_iter, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
TreeBuilder_dealloc(TreeBuilder* self)
|
|
{
|
|
Py_XDECREF(self->repo);
|
|
git_treebuilder_free(self->bld);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
TreeBuilder_insert(TreeBuilder *self, TreeEntry *py_tentry)
|
|
{
|
|
int err, attr;
|
|
const git_oid *oid;
|
|
const char *fname;
|
|
const git_tree_entry *tentry;
|
|
|
|
tentry = py_tentry->entry;
|
|
fname = git_tree_entry_name(tentry);
|
|
oid = git_tree_entry_id(tentry);
|
|
attr = git_tree_entry_attributes(tentry);
|
|
|
|
err = git_treebuilder_insert(NULL, self->bld, fname, oid, attr);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
TreeBuilder_write(TreeBuilder *self)
|
|
{
|
|
int err;
|
|
git_oid oid;
|
|
|
|
err = git_treebuilder_write(&oid, self->repo->repo, self->bld);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return git_oid_to_python(&oid);
|
|
}
|
|
|
|
static PyObject *
|
|
TreeBuilder_remove(TreeBuilder *self, PyObject *py_filename)
|
|
{
|
|
char *filename;
|
|
int err;
|
|
|
|
filename = py_path_to_c_str(py_filename);
|
|
if (filename == NULL)
|
|
return NULL;
|
|
|
|
err = git_treebuilder_remove(self->bld, filename);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
TreeBuilder_clear(TreeBuilder *self)
|
|
{
|
|
git_treebuilder_clear(self->bld);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyMethodDef TreeBuilder_methods[] = {
|
|
{"insert", (PyCFunction)TreeBuilder_insert, METH_O,
|
|
"Insert or replace an entry in the treebuilder"},
|
|
{"write", (PyCFunction)TreeBuilder_write, METH_NOARGS,
|
|
"Write the tree to the given repository"},
|
|
{"remove", (PyCFunction)TreeBuilder_remove, METH_O,
|
|
"Remove an entry from the builder"},
|
|
{"clear", (PyCFunction)TreeBuilder_clear, METH_NOARGS,
|
|
"Clear all the entries in the builder"},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
static PyTypeObject TreeBuilderType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.TreeBuilder", /* tp_name */
|
|
sizeof(TreeBuilder), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)TreeBuilder_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"TreeBuilder objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
TreeBuilder_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
TreeIter_dealloc(TreeIter *self)
|
|
{
|
|
Py_CLEAR(self->owner);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static TreeEntry *
|
|
TreeIter_iternext(TreeIter *self)
|
|
{
|
|
const git_tree_entry *tree_entry;
|
|
|
|
tree_entry = git_tree_entry_byindex(self->owner->tree, self->i);
|
|
if (!tree_entry)
|
|
return NULL;
|
|
|
|
self->i += 1;
|
|
return (TreeEntry*)wrap_tree_entry(tree_entry, self->owner->repo);
|
|
}
|
|
|
|
static PyTypeObject TreeIterType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.TreeIter", /* tp_name */
|
|
sizeof(TreeIter), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)TreeIter_dealloc , /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT |
|
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
0, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)TreeIter_iternext, /* tp_iternext */
|
|
};
|
|
|
|
static PyGetSetDef Blob_getseters[] = {
|
|
{"data", (getter)Object_read_raw, NULL, "raw data", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject BlobType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Blob", /* tp_name */
|
|
sizeof(Blob), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"Blob objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
Blob_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static PyObject *
|
|
Tag_get_target(Tag *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
oid = git_tag_target_oid(self->tag);
|
|
return git_oid_to_python(oid->id);
|
|
}
|
|
|
|
static PyObject *
|
|
Tag_get_name(Tag *self)
|
|
{
|
|
const char *name;
|
|
name = git_tag_name(self->tag);
|
|
if (!name)
|
|
Py_RETURN_NONE;
|
|
return to_unicode(name, "utf-8", "strict");
|
|
}
|
|
|
|
static PyObject *
|
|
Tag_get_tagger(Tag *self)
|
|
{
|
|
const git_signature *signature = git_tag_tagger(self->tag);
|
|
if (!signature)
|
|
Py_RETURN_NONE;
|
|
|
|
return build_signature((Object*)self, signature, "utf-8");
|
|
}
|
|
|
|
static PyObject *
|
|
Tag_get_message(Tag *self)
|
|
{
|
|
const char *message;
|
|
message = git_tag_message(self->tag);
|
|
if (!message)
|
|
Py_RETURN_NONE;
|
|
return to_unicode(message, "utf-8", "strict");
|
|
}
|
|
|
|
static PyObject *
|
|
Tag_get_raw_message(Tag *self)
|
|
{
|
|
return PyString_FromString(git_tag_message(self->tag));
|
|
}
|
|
|
|
static PyGetSetDef Tag_getseters[] = {
|
|
{"target", (getter)Tag_get_target, NULL, "tagged object", NULL},
|
|
{"name", (getter)Tag_get_name, NULL, "tag name", NULL},
|
|
{"tagger", (getter)Tag_get_tagger, NULL, "tagger", NULL},
|
|
{"message", (getter)Tag_get_message, NULL, "tag message", NULL},
|
|
{"_message", (getter)Tag_get_raw_message, NULL, "tag message (bytes)", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject TagType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Tag", /* tp_name */
|
|
sizeof(Tag), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"Tag objects", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
Tag_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static int
|
|
Index_init(Index *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
char *path;
|
|
int err;
|
|
|
|
if (kwds) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Index takes no keyword arguments");
|
|
return -1;
|
|
}
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &path))
|
|
return -1;
|
|
|
|
err = git_index_open(&self->index, path);
|
|
if (err < 0) {
|
|
Error_set_str(err, path);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
Index_dealloc(Index* self)
|
|
{
|
|
PyObject_GC_UnTrack(self);
|
|
Py_XDECREF(self->repo);
|
|
git_index_free(self->index);
|
|
PyObject_GC_Del(self);
|
|
}
|
|
|
|
static int
|
|
Index_traverse(Index *self, visitproc visit, void *arg)
|
|
{
|
|
Py_VISIT(self->repo);
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_add(Index *self, PyObject *args)
|
|
{
|
|
int err;
|
|
const char *path;
|
|
int stage=0;
|
|
|
|
if (!PyArg_ParseTuple(args, "s|i", &path, &stage))
|
|
return NULL;
|
|
|
|
err = git_index_add(self->index, path, stage);
|
|
if (err < 0)
|
|
return Error_set_str(err, path);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_clear(Index *self)
|
|
{
|
|
git_index_clear(self->index);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_find(Index *self, PyObject *py_path)
|
|
{
|
|
char *path;
|
|
long idx;
|
|
|
|
path = PyString_AsString(py_path);
|
|
if (!path)
|
|
return NULL;
|
|
|
|
idx = (long)git_index_find(self->index, path);
|
|
if (idx < 0)
|
|
return Error_set_str(idx, path);
|
|
|
|
return PyInt_FromLong(idx);
|
|
}
|
|
|
|
static PyObject *
|
|
Index_read(Index *self)
|
|
{
|
|
int err;
|
|
|
|
err = git_index_read(self->index);
|
|
if (err < GIT_SUCCESS)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_write(Index *self)
|
|
{
|
|
int err;
|
|
|
|
err = git_index_write(self->index);
|
|
if (err < GIT_SUCCESS)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
/* This is an internal function, used by Index_getitem and Index_setitem */
|
|
static int
|
|
Index_get_position(Index *self, PyObject *value)
|
|
{
|
|
char *path;
|
|
int idx;
|
|
|
|
/* Case 1: integer */
|
|
if (PyInt_Check(value)) {
|
|
idx = (int)PyInt_AsLong(value);
|
|
if (idx == -1 && PyErr_Occurred())
|
|
return -1;
|
|
if (idx < 0) {
|
|
PyErr_SetObject(PyExc_ValueError, value);
|
|
return -1;
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
/* Case 2: byte or text string */
|
|
path = py_path_to_c_str(value);
|
|
if (!path)
|
|
return -1;
|
|
idx = git_index_find(self->index, path);
|
|
if (idx < 0) {
|
|
Error_set_str(idx, path);
|
|
return -1;
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
static int
|
|
Index_contains(Index *self, PyObject *value)
|
|
{
|
|
char *path;
|
|
int idx;
|
|
|
|
path = py_path_to_c_str(value);
|
|
if (!path)
|
|
return -1;
|
|
idx = git_index_find(self->index, path);
|
|
if (idx == GIT_ENOTFOUND)
|
|
return 0;
|
|
if (idx < 0) {
|
|
Error_set_str(idx, path);
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_iter(Index *self)
|
|
{
|
|
IndexIter *iter;
|
|
|
|
iter = PyObject_New(IndexIter, &IndexIterType);
|
|
if (iter) {
|
|
Py_INCREF(self);
|
|
iter->owner = self;
|
|
iter->i = 0;
|
|
}
|
|
return (PyObject*)iter;
|
|
}
|
|
|
|
static Py_ssize_t
|
|
Index_len(Index *self)
|
|
{
|
|
return (Py_ssize_t)git_index_entrycount(self->index);
|
|
}
|
|
|
|
static PyObject *
|
|
wrap_index_entry(git_index_entry *entry, Index *index)
|
|
{
|
|
IndexEntry *py_entry;
|
|
|
|
py_entry = PyObject_New(IndexEntry, &IndexEntryType);
|
|
if (py_entry)
|
|
py_entry->entry = entry;
|
|
|
|
return (PyObject*)py_entry;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_getitem(Index *self, PyObject *value)
|
|
{
|
|
int idx;
|
|
git_index_entry *index_entry;
|
|
|
|
idx = Index_get_position(self, value);
|
|
if (idx == -1)
|
|
return NULL;
|
|
|
|
index_entry = git_index_get(self->index, idx);
|
|
if (!index_entry) {
|
|
PyErr_SetObject(PyExc_KeyError, value);
|
|
return NULL;
|
|
}
|
|
|
|
return wrap_index_entry(index_entry, self);
|
|
}
|
|
|
|
static int
|
|
Index_setitem(Index *self, PyObject *key, PyObject *value)
|
|
{
|
|
int err;
|
|
int idx;
|
|
|
|
if (value) {
|
|
PyErr_SetString(PyExc_NotImplementedError,
|
|
"set item on index not yet implemented");
|
|
return -1;
|
|
}
|
|
|
|
idx = Index_get_position(self, key);
|
|
if (idx == -1)
|
|
return -1;
|
|
|
|
err = git_index_remove(self->index, idx);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_read_tree(Index *self, PyObject *value)
|
|
{
|
|
git_oid oid;
|
|
git_tree *tree;
|
|
int err, len;
|
|
|
|
len = py_str_to_git_oid(value, &oid);
|
|
if (len < 0)
|
|
return NULL;
|
|
|
|
err = git_tree_lookup_prefix(&tree, self->repo->repo, &oid,
|
|
(unsigned int)len);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
err = git_index_read_tree(self->index, tree);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Index_write_tree(Index *self)
|
|
{
|
|
git_oid oid;
|
|
int err;
|
|
|
|
err = git_tree_create_fromindex(&oid, self->index);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return git_oid_to_python(oid.id);
|
|
}
|
|
|
|
static PyMethodDef Index_methods[] = {
|
|
{"add", (PyCFunction)Index_add, METH_VARARGS,
|
|
"Add or update an index entry from a file in disk."},
|
|
{"clear", (PyCFunction)Index_clear, METH_NOARGS,
|
|
"Clear the contents (all the entries) of an index object."},
|
|
{"_find", (PyCFunction)Index_find, METH_O,
|
|
"Find the first index of any entries which point to given path in the"
|
|
" Git index."},
|
|
{"read", (PyCFunction)Index_read, METH_NOARGS,
|
|
"Update the contents of an existing index object in memory by reading"
|
|
" from the hard disk."},
|
|
{"write", (PyCFunction)Index_write, METH_NOARGS,
|
|
"Write an existing index object from memory back to disk using an"
|
|
" atomic file lock."},
|
|
{"read_tree", (PyCFunction)Index_read_tree, METH_O,
|
|
"Update the index file from the given tree object."},
|
|
{"write_tree", (PyCFunction)Index_write_tree, METH_NOARGS,
|
|
"Create a tree object from the index file, return its oid."},
|
|
{NULL}
|
|
};
|
|
|
|
static PySequenceMethods Index_as_sequence = {
|
|
0, /* sq_length */
|
|
0, /* sq_concat */
|
|
0, /* sq_repeat */
|
|
0, /* sq_item */
|
|
0, /* sq_slice */
|
|
0, /* sq_ass_item */
|
|
0, /* sq_ass_slice */
|
|
(objobjproc)Index_contains, /* sq_contains */
|
|
};
|
|
|
|
static PyMappingMethods Index_as_mapping = {
|
|
(lenfunc)Index_len, /* mp_length */
|
|
(binaryfunc)Index_getitem, /* mp_subscript */
|
|
(objobjargproc)Index_setitem, /* mp_ass_subscript */
|
|
};
|
|
|
|
static PyTypeObject IndexType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Index", /* tp_name */
|
|
sizeof(Index), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Index_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
&Index_as_sequence, /* tp_as_sequence */
|
|
&Index_as_mapping, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT |
|
|
Py_TPFLAGS_BASETYPE |
|
|
Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
|
"Index file", /* tp_doc */
|
|
(traverseproc)Index_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
(getiterfunc)Index_iter, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
Index_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
(initproc)Index_init, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
|
|
static void
|
|
IndexIter_dealloc(IndexIter *self)
|
|
{
|
|
Py_CLEAR(self->owner);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
IndexIter_iternext(IndexIter *self)
|
|
{
|
|
git_index_entry *index_entry;
|
|
|
|
index_entry = git_index_get(self->owner->index, self->i);
|
|
if (!index_entry)
|
|
return NULL;
|
|
|
|
self->i += 1;
|
|
return wrap_index_entry(index_entry, self->owner);
|
|
}
|
|
|
|
static PyTypeObject IndexIterType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.IndexIter", /* tp_name */
|
|
sizeof(IndexIter), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)IndexIter_dealloc , /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT |
|
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
0, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)IndexIter_iternext, /* tp_iternext */
|
|
};
|
|
|
|
static void
|
|
IndexEntry_dealloc(IndexEntry *self)
|
|
{
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
IndexEntry_get_mode(IndexEntry *self)
|
|
{
|
|
return PyInt_FromLong(self->entry->mode);
|
|
}
|
|
|
|
static PyObject *
|
|
IndexEntry_get_path(IndexEntry *self)
|
|
{
|
|
return to_path(self->entry->path);
|
|
}
|
|
|
|
static PyObject *
|
|
IndexEntry_get_oid(IndexEntry *self)
|
|
{
|
|
return git_oid_to_python(self->entry->oid.id);
|
|
}
|
|
|
|
static PyObject *
|
|
IndexEntry_get_hex(IndexEntry *self)
|
|
{
|
|
return git_oid_to_py_str(&self->entry->oid);
|
|
}
|
|
|
|
static PyGetSetDef IndexEntry_getseters[] = {
|
|
{"mode", (getter)IndexEntry_get_mode, NULL, "mode", NULL},
|
|
{"path", (getter)IndexEntry_get_path, NULL, "path", NULL},
|
|
{"oid", (getter)IndexEntry_get_oid, NULL, "object id", NULL},
|
|
{"hex", (getter)IndexEntry_get_hex, NULL, "hex oid", NULL},
|
|
{NULL},
|
|
};
|
|
|
|
static PyTypeObject IndexEntryType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.IndexEntry", /* tp_name */
|
|
sizeof(IndexEntry), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)IndexEntry_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
"Index entry", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
IndexEntry_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
Walker_dealloc(Walker *self)
|
|
{
|
|
git_revwalk_free(self->walk);
|
|
Py_DECREF(self->repo);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_hide(Walker *self, PyObject *py_hex)
|
|
{
|
|
int err;
|
|
git_oid oid;
|
|
|
|
err = py_str_to_git_oid_expand(self->repo->repo, py_hex, &oid);
|
|
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
err = git_revwalk_hide(self->walk, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_push(Walker *self, PyObject *py_hex)
|
|
{
|
|
int err;
|
|
git_oid oid;
|
|
|
|
err = py_str_to_git_oid_expand(self->repo->repo, py_hex, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
err = git_revwalk_push(self->walk, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_sort(Walker *self, PyObject *py_sort_mode)
|
|
{
|
|
int sort_mode;
|
|
|
|
sort_mode = (int)PyInt_AsLong(py_sort_mode);
|
|
if (sort_mode == -1 && PyErr_Occurred())
|
|
return NULL;
|
|
|
|
git_revwalk_sorting(self->walk, sort_mode);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_reset(Walker *self)
|
|
{
|
|
git_revwalk_reset(self->walk);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_iter(Walker *self)
|
|
{
|
|
Py_INCREF(self);
|
|
return (PyObject*)self;
|
|
}
|
|
|
|
static PyObject *
|
|
Walker_iternext(Walker *self)
|
|
{
|
|
int err;
|
|
git_commit *commit;
|
|
Commit *py_commit;
|
|
git_oid oid;
|
|
|
|
err = git_revwalk_next(&oid, self->walk);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
err = git_commit_lookup(&commit, self->repo->repo, &oid);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
py_commit = PyObject_New(Commit, &CommitType);
|
|
if (py_commit) {
|
|
py_commit->commit = commit;
|
|
Py_INCREF(self->repo);
|
|
py_commit->repo = self->repo;
|
|
}
|
|
return (PyObject*)py_commit;
|
|
}
|
|
|
|
static PyMethodDef Walker_methods[] = {
|
|
{"hide", (PyCFunction)Walker_hide, METH_O,
|
|
"Mark a commit (and its ancestors) uninteresting for the output."},
|
|
{"push", (PyCFunction)Walker_push, METH_O,
|
|
"Mark a commit to start traversal from."},
|
|
{"reset", (PyCFunction)Walker_reset, METH_NOARGS,
|
|
"Reset the walking machinery for reuse."},
|
|
{"sort", (PyCFunction)Walker_sort, METH_O,
|
|
"Change the sorting mode (this resets the walker)."},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject WalkerType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Walker", /* tp_name */
|
|
sizeof(Walker), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Walker_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
"Revision walker", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
(getiterfunc)Walker_iter, /* tp_iter */
|
|
(iternextfunc)Walker_iternext, /* tp_iternext */
|
|
Walker_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static void
|
|
Reference_dealloc(Reference *self)
|
|
{
|
|
git_reference_free(self->reference);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_delete(Reference *self, PyObject *args)
|
|
{
|
|
int err;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Delete the reference */
|
|
err = git_reference_delete(self->reference);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
self->reference = NULL; /* Invalidate the pointer */
|
|
Py_RETURN_NONE; /* Return None */
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_rename(Reference *self, PyObject *py_name)
|
|
{
|
|
char *c_name;
|
|
int err;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Get the C name */
|
|
c_name = py_path_to_c_str(py_name);
|
|
if (c_name == NULL)
|
|
return NULL;
|
|
|
|
/* Rename */
|
|
err = git_reference_rename(self->reference, c_name, 0);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
Py_RETURN_NONE; /* Return None */
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_reload(Reference *self)
|
|
{
|
|
int err;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
err = git_reference_reload(self->reference);
|
|
if (err < 0) {
|
|
self->reference = NULL;
|
|
return Error_set(err);
|
|
}
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
Reference_resolve(Reference *self, PyObject *args)
|
|
{
|
|
git_reference *c_reference;
|
|
int err;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Direct: reload */
|
|
if (git_reference_type(self->reference) == GIT_REF_OID) {
|
|
err = git_reference_reload(self->reference);
|
|
if (err < 0) {
|
|
self->reference = NULL;
|
|
return Error_set(err);
|
|
}
|
|
Py_INCREF(self);
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
/* Symbolic: resolve */
|
|
err = git_reference_resolve(&c_reference, self->reference);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return wrap_reference(c_reference);
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_get_target(Reference *self)
|
|
{
|
|
const char * c_name;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Get the target */
|
|
c_name = git_reference_target(self->reference);
|
|
if (c_name == NULL) {
|
|
PyErr_SetString(PyExc_ValueError, "no target available");
|
|
return NULL;
|
|
}
|
|
|
|
/* Make a PyString and return it */
|
|
return to_path(c_name);
|
|
}
|
|
|
|
static int
|
|
Reference_set_target(Reference *self, PyObject *py_name)
|
|
{
|
|
char *c_name;
|
|
int err;
|
|
|
|
CHECK_REFERENCE_INT(self);
|
|
|
|
/* Get the C name */
|
|
c_name = py_path_to_c_str(py_name);
|
|
if (c_name == NULL)
|
|
return -1;
|
|
|
|
/* Set the new target */
|
|
err = git_reference_set_target(self->reference, c_name);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_get_name(Reference *self)
|
|
{
|
|
CHECK_REFERENCE(self);
|
|
return to_path(git_reference_name(self->reference));
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_get_oid(Reference *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Get the oid (only for "direct" references) */
|
|
oid = git_reference_oid(self->reference);
|
|
if (oid == NULL) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"oid is only available if the reference is direct "
|
|
"(i.e. not symbolic)");
|
|
return NULL;
|
|
}
|
|
|
|
/* Convert and return it */
|
|
return git_oid_to_python(oid->id);
|
|
}
|
|
|
|
static int
|
|
Reference_set_oid(Reference *self, PyObject *py_hex)
|
|
{
|
|
git_oid oid;
|
|
int err;
|
|
|
|
CHECK_REFERENCE_INT(self);
|
|
|
|
/* Get the oid */
|
|
err = py_str_to_git_oid_expand(git_reference_owner(self->reference), py_hex, &oid);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
/* Set the oid */
|
|
err = git_reference_set_oid(self->reference, &oid);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_get_hex(Reference *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
CHECK_REFERENCE(self);
|
|
|
|
/* Get the oid (only for "direct" references) */
|
|
oid = git_reference_oid(self->reference);
|
|
if (oid == NULL) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"oid is only available if the reference is direct "
|
|
"(i.e. not symbolic)");
|
|
return NULL;
|
|
}
|
|
|
|
/* Convert and return it */
|
|
return git_oid_to_py_str(oid);
|
|
}
|
|
|
|
static PyObject *
|
|
Reference_get_type(Reference *self)
|
|
{
|
|
git_rtype c_type;
|
|
|
|
CHECK_REFERENCE(self);
|
|
c_type = git_reference_type(self->reference);
|
|
return PyInt_FromLong(c_type);
|
|
}
|
|
|
|
static PyMethodDef Reference_methods[] = {
|
|
{"delete", (PyCFunction)Reference_delete, METH_NOARGS,
|
|
"Delete this reference. It will no longer be valid!"},
|
|
{"rename", (PyCFunction)Reference_rename, METH_O,
|
|
"Rename the reference."},
|
|
{"reload", (PyCFunction)Reference_reload, METH_NOARGS,
|
|
"Reload the reference from the file-system."},
|
|
{"resolve", (PyCFunction)Reference_resolve, METH_NOARGS,
|
|
"Resolve a symbolic reference and return a direct reference."},
|
|
{NULL}
|
|
};
|
|
|
|
static PyGetSetDef Reference_getseters[] = {
|
|
{"name", (getter)Reference_get_name, NULL,
|
|
"The full name of a reference.", NULL},
|
|
{"oid", (getter)Reference_get_oid, (setter)Reference_set_oid, "object id",
|
|
NULL},
|
|
{"hex", (getter)Reference_get_hex, NULL, "hex oid", NULL},
|
|
{"target", (getter)Reference_get_target, (setter)Reference_set_target,
|
|
"target", NULL},
|
|
{"type", (getter)Reference_get_type, NULL,
|
|
"type (GIT_REF_OID, GIT_REF_SYMBOLIC or GIT_REF_PACKED).", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject ReferenceType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Reference", /* tp_name */
|
|
sizeof(Reference), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Reference_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
"Reference", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
Reference_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
Reference_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static int
|
|
Signature_init(Signature *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *py_name;
|
|
char *name, *email, *encoding = NULL;
|
|
long long time;
|
|
int offset;
|
|
int err;
|
|
git_signature *signature;
|
|
|
|
if (kwds) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Signature takes no keyword arguments");
|
|
return -1;
|
|
}
|
|
|
|
if (!PyArg_ParseTuple(args, "OsLi|s",
|
|
&py_name, &email, &time, &offset, &encoding))
|
|
return -1;
|
|
|
|
name = py_str_to_c_str(py_name, encoding);
|
|
if (name == NULL)
|
|
return -1;
|
|
|
|
err = git_signature_new(&signature, name, email, time, offset);
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
self->obj = NULL;
|
|
self->signature = signature;
|
|
|
|
if (encoding) {
|
|
self->encoding = strdup(encoding);
|
|
if (self->encoding == NULL) {
|
|
PyErr_NoMemory();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
Signature_dealloc(Signature *self)
|
|
{
|
|
if (self->obj)
|
|
Py_DECREF(self->obj);
|
|
else {
|
|
git_signature_free((git_signature*)self->signature);
|
|
free((void*)self->encoding);
|
|
}
|
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_encoding(Signature *self)
|
|
{
|
|
const char *encoding;
|
|
|
|
encoding = self->encoding;
|
|
if (encoding == NULL)
|
|
encoding = "utf-8";
|
|
|
|
return to_encoding(encoding);
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_raw_name(Signature *self)
|
|
{
|
|
return to_bytes(self->signature->name);
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_raw_email(Signature *self)
|
|
{
|
|
return to_bytes(self->signature->email);
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_name(Signature *self)
|
|
{
|
|
return to_unicode(self->signature->name, self->encoding, "strict");
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_email(Signature *self)
|
|
{
|
|
return to_unicode(self->signature->email, self->encoding, "strict");
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_time(Signature *self)
|
|
{
|
|
return PyInt_FromLong(self->signature->when.time);
|
|
}
|
|
|
|
static PyObject *
|
|
Signature_get_offset(Signature *self)
|
|
{
|
|
return PyInt_FromLong(self->signature->when.offset);
|
|
}
|
|
|
|
static PyGetSetDef Signature_getseters[] = {
|
|
{"_encoding", (getter)Signature_get_encoding, NULL, "encoding", NULL},
|
|
{"_name", (getter)Signature_get_raw_name, NULL, "Name (bytes)", NULL},
|
|
{"_email", (getter)Signature_get_raw_email, NULL, "Email (bytes)", NULL},
|
|
{"name", (getter)Signature_get_name, NULL, "Name", NULL},
|
|
{"email", (getter)Signature_get_email, NULL, "Email", NULL},
|
|
{"time", (getter)Signature_get_time, NULL, "Time", NULL},
|
|
{"offset", (getter)Signature_get_offset, NULL, "Offset", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyTypeObject SignatureType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"pygit2.Signature", /* tp_name */
|
|
sizeof(Signature), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)Signature_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
"Signature", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
Signature_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
(initproc)Signature_init, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
static PyObject *
|
|
init_repository(PyObject *self, PyObject *args)
|
|
{
|
|
git_repository *repo;
|
|
Repository *py_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);
|
|
|
|
py_repo = PyObject_GC_New(Repository, &RepositoryType);
|
|
if (py_repo) {
|
|
py_repo->repo = repo;
|
|
py_repo->index = NULL;
|
|
PyObject_GC_Track(py_repo);
|
|
return (PyObject*)py_repo;
|
|
}
|
|
|
|
git_repository_free(repo);
|
|
return NULL;
|
|
};
|
|
|
|
static PyObject *
|
|
discover_repository(PyObject *self, PyObject *args)
|
|
{
|
|
const char *path;
|
|
int across_fs = 0;
|
|
const char *ceiling_dirs = NULL;
|
|
char repo_path[MAXPATHLEN];
|
|
int err;
|
|
|
|
if (!PyArg_ParseTuple(args, "s|Is", &path, &across_fs, &ceiling_dirs))
|
|
return NULL;
|
|
|
|
err = git_repository_discover(repo_path, sizeof(repo_path),
|
|
path, across_fs, ceiling_dirs);
|
|
if (err < 0)
|
|
return Error_set_str(err, path);
|
|
|
|
return to_path(repo_path);
|
|
};
|
|
|
|
static PyMethodDef module_methods[] = {
|
|
{"init_repository", init_repository, METH_VARARGS,
|
|
"Creates a new Git repository in the given folder."},
|
|
{"discover_repository", discover_repository, METH_VARARGS,
|
|
"Look for a git repository and return its path."},
|
|
{NULL}
|
|
};
|
|
|
|
PyObject*
|
|
moduleinit(PyObject* m)
|
|
{
|
|
if (m == NULL)
|
|
return NULL;
|
|
|
|
GitError = PyErr_NewException("pygit2.GitError", NULL, NULL);
|
|
|
|
RepositoryType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&RepositoryType) < 0)
|
|
return NULL;
|
|
|
|
/* Do not set 'tp_new' for Git objects. To create Git objects use the
|
|
* Repository.create_XXX methods */
|
|
if (PyType_Ready(&ObjectType) < 0)
|
|
return NULL;
|
|
CommitType.tp_base = &ObjectType;
|
|
if (PyType_Ready(&CommitType) < 0)
|
|
return NULL;
|
|
TreeType.tp_base = &ObjectType;
|
|
if (PyType_Ready(&TreeType) < 0)
|
|
return NULL;
|
|
BlobType.tp_base = &ObjectType;
|
|
if (PyType_Ready(&BlobType) < 0)
|
|
return NULL;
|
|
TagType.tp_base = &ObjectType;
|
|
if (PyType_Ready(&TagType) < 0)
|
|
return NULL;
|
|
|
|
TreeEntryType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&TreeEntryType) < 0)
|
|
return NULL;
|
|
IndexType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&IndexType) < 0)
|
|
return NULL;
|
|
IndexEntryType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&IndexEntryType) < 0)
|
|
return NULL;
|
|
TreeBuilderType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&TreeBuilderType) < 0)
|
|
return NULL;
|
|
WalkerType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&WalkerType) < 0)
|
|
return NULL;
|
|
ReferenceType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&ReferenceType) < 0)
|
|
return NULL;
|
|
SignatureType.tp_new = PyType_GenericNew;
|
|
if (PyType_Ready(&SignatureType) < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(GitError);
|
|
PyModule_AddObject(m, "GitError", GitError);
|
|
|
|
Py_INCREF(&RepositoryType);
|
|
PyModule_AddObject(m, "Repository", (PyObject *)&RepositoryType);
|
|
|
|
Py_INCREF(&ObjectType);
|
|
PyModule_AddObject(m, "Object", (PyObject *)&ObjectType);
|
|
|
|
Py_INCREF(&CommitType);
|
|
PyModule_AddObject(m, "Commit", (PyObject *)&CommitType);
|
|
|
|
Py_INCREF(&TreeEntryType);
|
|
PyModule_AddObject(m, "TreeEntry", (PyObject *)&TreeEntryType);
|
|
|
|
Py_INCREF(&TreeType);
|
|
PyModule_AddObject(m, "Tree", (PyObject *)&TreeType);
|
|
|
|
Py_INCREF(&BlobType);
|
|
PyModule_AddObject(m, "Blob", (PyObject *)&BlobType);
|
|
|
|
Py_INCREF(&TagType);
|
|
PyModule_AddObject(m, "Tag", (PyObject *)&TagType);
|
|
|
|
Py_INCREF(&IndexType);
|
|
PyModule_AddObject(m, "Index", (PyObject *)&IndexType);
|
|
|
|
Py_INCREF(&IndexEntryType);
|
|
PyModule_AddObject(m, "IndexEntry", (PyObject *)&IndexEntryType);
|
|
|
|
Py_INCREF(&ReferenceType);
|
|
PyModule_AddObject(m, "Reference", (PyObject *)&ReferenceType);
|
|
|
|
Py_INCREF(&SignatureType);
|
|
PyModule_AddObject(m, "Signature", (PyObject *)&SignatureType);
|
|
|
|
PyModule_AddIntConstant(m, "GIT_OBJ_ANY", GIT_OBJ_ANY);
|
|
PyModule_AddIntConstant(m, "GIT_OBJ_COMMIT", GIT_OBJ_COMMIT);
|
|
PyModule_AddIntConstant(m, "GIT_OBJ_TREE", GIT_OBJ_TREE);
|
|
PyModule_AddIntConstant(m, "GIT_OBJ_BLOB", GIT_OBJ_BLOB);
|
|
PyModule_AddIntConstant(m, "GIT_OBJ_TAG", GIT_OBJ_TAG);
|
|
PyModule_AddIntConstant(m, "GIT_SORT_NONE", GIT_SORT_NONE);
|
|
PyModule_AddIntConstant(m, "GIT_SORT_TOPOLOGICAL", GIT_SORT_TOPOLOGICAL);
|
|
PyModule_AddIntConstant(m, "GIT_SORT_TIME", GIT_SORT_TIME);
|
|
PyModule_AddIntConstant(m, "GIT_SORT_REVERSE", GIT_SORT_REVERSE);
|
|
PyModule_AddIntConstant(m, "GIT_REF_OID", GIT_REF_OID);
|
|
PyModule_AddIntConstant(m, "GIT_REF_SYMBOLIC", GIT_REF_SYMBOLIC);
|
|
PyModule_AddIntConstant(m, "GIT_REF_PACKED", GIT_REF_PACKED);
|
|
|
|
/* Git status flags */
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_CURRENT", GIT_STATUS_CURRENT);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_INDEX_NEW", GIT_STATUS_INDEX_NEW);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_INDEX_MODIFIED",
|
|
GIT_STATUS_INDEX_MODIFIED);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_INDEX_DELETED" ,
|
|
GIT_STATUS_INDEX_DELETED);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_WT_NEW", GIT_STATUS_WT_NEW);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_WT_MODIFIED" ,
|
|
GIT_STATUS_WT_MODIFIED);
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_WT_DELETED", GIT_STATUS_WT_DELETED);
|
|
|
|
/* Flags for ignored files */
|
|
PyModule_AddIntConstant(m, "GIT_STATUS_IGNORED", GIT_STATUS_IGNORED);
|
|
|
|
return m;
|
|
}
|
|
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
PyMODINIT_FUNC
|
|
initpygit2(void)
|
|
{
|
|
PyObject* m;
|
|
m = Py_InitModule3("pygit2", module_methods,
|
|
"Python bindings for libgit2.");
|
|
moduleinit(m);
|
|
}
|
|
#else
|
|
static struct PyModuleDef moduledef = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"pygit2", /* m_name */
|
|
"Python bindings for libgit2.", /* m_doc */
|
|
-1, /* m_size */
|
|
module_methods, /* m_methods */
|
|
NULL, /* m_reload */
|
|
NULL, /* m_traverse */
|
|
NULL, /* m_clear */
|
|
NULL, /* m_free */
|
|
};
|
|
|
|
PyMODINIT_FUNC
|
|
PyInit_pygit2(void)
|
|
{
|
|
PyObject* m;
|
|
m = PyModule_Create(&moduledef);
|
|
return moduleinit(m);
|
|
}
|
|
#endif
|