Merge branch 'oid'
This commit is contained in:
@@ -5,10 +5,66 @@ Git objects
|
||||
.. contents:: Contents
|
||||
:local:
|
||||
|
||||
In the first place Git is a key-value storage system. The keys are called
|
||||
OIDs, for Object id, and the values stored are called Objects.
|
||||
|
||||
In the first place Git is a key-value storage system. The values stored are
|
||||
called *objects*, there are four types (commits, trees, blobs and tags),
|
||||
for each type pygit2 has a Python class::
|
||||
Oids
|
||||
=================
|
||||
|
||||
The oid is the `SHA-1 <http://en.wikipedia.org/wiki/SHA-1>`_ hash of an
|
||||
object. It is 20 bytes long:
|
||||
|
||||
- When we represent an oid as a 20 bytes Python string, we say it is a raw
|
||||
oid.
|
||||
|
||||
- When we represent an oid as a 40 chars Python string, we sayt it is a hex
|
||||
oid.
|
||||
|
||||
However, most of the time we will use the Oid type. We can explicetly create
|
||||
an Oid object from its raw or hexadecimal form::
|
||||
|
||||
>>> hex = "cff3ceaefc955f0dbe1957017db181bc49913781"
|
||||
>>> oid1 = Oid(hex=hex)
|
||||
|
||||
>>> from binascii import unhexlify
|
||||
>>> raw = unhexlify(hex)
|
||||
>>> oid2 = Oid(raw=raw)
|
||||
|
||||
>>> print oid1 == oid2
|
||||
True
|
||||
|
||||
And in the opposite direction, we can get the raw or hexadecimal form from
|
||||
an Oid object:
|
||||
|
||||
.. autoattribute:: pygit2.Oid.raw
|
||||
.. autoattribute:: pygit2.Oid.hex
|
||||
|
||||
The Oid type supports:
|
||||
|
||||
- rich comparisons, not just for equality, also: lesser-than, lesser-or-equal,
|
||||
etc.
|
||||
|
||||
- hashing, so Oid objects can be used as keys in a dictionary
|
||||
|
||||
|
||||
Python 2 and Python 3
|
||||
---------------------
|
||||
|
||||
There is a difference on how the library handles hex oids, depending on
|
||||
whether we are using Python 2 or 3.
|
||||
|
||||
- In Python 2, we can represent an hexadecimal oid using a bytes string
|
||||
(``str``) or a text string (``unicode``)
|
||||
|
||||
- In Python 3, hexadecimal oids can only be represented using unicode
|
||||
strings.
|
||||
|
||||
|
||||
Objects
|
||||
=================
|
||||
|
||||
There are four types (commits, trees, blobs and tags), for each type pygit2
|
||||
has a Python class::
|
||||
|
||||
>>> # Show commits and trees
|
||||
>>> commit
|
||||
|
@@ -423,7 +423,7 @@ Index_write_tree(Index *self)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
PyMethodDef Index_methods[] = {
|
||||
@@ -585,7 +585,7 @@ PyDoc_STRVAR(IndexEntry_oid__doc__, "Object id.");
|
||||
PyObject *
|
||||
IndexEntry_oid__get__(IndexEntry *self)
|
||||
{
|
||||
return git_oid_to_python(self->entry->oid.id);
|
||||
return git_oid_to_python(&self->entry->oid);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -72,7 +72,7 @@ PyDoc_STRVAR(Note_oid__doc__,
|
||||
PyObject *
|
||||
Note_oid__get__(Note *self)
|
||||
{
|
||||
return git_oid_to_py_str(git_note_oid(self->note));
|
||||
return git_oid_to_python(git_note_oid(self->note));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -60,7 +60,7 @@ Object_oid__get__(Object *self)
|
||||
oid = git_object_id(self->obj);
|
||||
assert(oid);
|
||||
|
||||
return git_oid_to_python(oid->id);
|
||||
return git_oid_to_python(oid);
|
||||
}
|
||||
|
||||
|
||||
|
235
src/oid.c
235
src/oid.c
@@ -32,56 +32,84 @@
|
||||
#include "error.h"
|
||||
#include "oid.h"
|
||||
|
||||
PyTypeObject OidType;
|
||||
|
||||
|
||||
PyObject *
|
||||
git_oid_to_python(const git_oid *oid)
|
||||
{
|
||||
Oid *py_oid;
|
||||
|
||||
py_oid = PyObject_New(Oid, &OidType);
|
||||
git_oid_cpy(&(py_oid->oid), oid);
|
||||
return (PyObject*)py_oid;
|
||||
}
|
||||
|
||||
int
|
||||
py_str_to_git_oid(PyObject *py_str, git_oid *oid)
|
||||
_oid_from_hex(PyObject *py_oid, git_oid *oid)
|
||||
{
|
||||
PyObject *py_hex;
|
||||
char *hex_or_bin;
|
||||
int err;
|
||||
char *hex;
|
||||
Py_ssize_t len;
|
||||
|
||||
/* Case 1: raw sha */
|
||||
if (PyBytes_Check(py_str)) {
|
||||
err = PyBytes_AsStringAndSize(py_str, &hex_or_bin, &len);
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
/* Bytes (only supported in Python 2) */
|
||||
if (PyBytes_Check(py_oid)) {
|
||||
err = PyBytes_AsStringAndSize(py_oid, &hex, &len);
|
||||
if (err)
|
||||
return -1;
|
||||
if (len > GIT_OID_RAWSZ) {
|
||||
PyErr_SetObject(PyExc_ValueError, py_str);
|
||||
|
||||
err = git_oid_fromstrn(oid, hex, len);
|
||||
if (err < 0) {
|
||||
PyErr_SetObject(Error_type(err), py_oid);
|
||||
return -1;
|
||||
}
|
||||
memcpy(oid->id, (const unsigned char*)hex_or_bin, len);
|
||||
return len * 2;
|
||||
}
|
||||
|
||||
/* Case 2: hex sha */
|
||||
if (PyUnicode_Check(py_str)) {
|
||||
py_hex = PyUnicode_AsASCIIString(py_str);
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Unicode */
|
||||
if (PyUnicode_Check(py_oid)) {
|
||||
py_hex = PyUnicode_AsASCIIString(py_oid);
|
||||
if (py_hex == NULL)
|
||||
return -1;
|
||||
err = PyBytes_AsStringAndSize(py_hex, &hex_or_bin, &len);
|
||||
|
||||
err = PyBytes_AsStringAndSize(py_hex, &hex, &len);
|
||||
if (err) {
|
||||
Py_DECREF(py_hex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = git_oid_fromstrn(oid, hex_or_bin, len);
|
||||
|
||||
err = git_oid_fromstrn(oid, hex, len);
|
||||
Py_DECREF(py_hex);
|
||||
|
||||
if (err < 0) {
|
||||
PyErr_SetObject(Error_type(err), py_str);
|
||||
PyErr_SetObject(Error_type(err), py_oid);
|
||||
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);
|
||||
PyErr_SetObject(PyExc_TypeError, py_oid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
py_str_to_git_oid(PyObject *py_oid, git_oid *oid)
|
||||
{
|
||||
/* Oid */
|
||||
if (PyObject_TypeCheck(py_oid, (PyTypeObject*)&OidType)) {
|
||||
git_oid_cpy(oid, &((Oid*)py_oid)->oid);
|
||||
return GIT_OID_RAWSZ;
|
||||
}
|
||||
|
||||
/* Hex */
|
||||
return _oid_from_hex(py_oid, oid);
|
||||
}
|
||||
|
||||
int
|
||||
py_str_to_git_oid_expand(git_repository *repo, PyObject *py_str, git_oid *oid)
|
||||
{
|
||||
@@ -122,6 +150,171 @@ git_oid_to_py_str(const git_oid *oid)
|
||||
char hex[GIT_OID_HEXSZ];
|
||||
|
||||
git_oid_fmt(hex, oid);
|
||||
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
return PyBytes_FromStringAndSize(hex, GIT_OID_HEXSZ);
|
||||
#else
|
||||
return to_unicode_n(hex, GIT_OID_HEXSZ, "utf-8", "strict");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Oid_init(Oid *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
char *keywords[] = {"raw", "hex", NULL};
|
||||
PyObject *raw = NULL, *hex = NULL;
|
||||
int err;
|
||||
char *bytes;
|
||||
Py_ssize_t len;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OO", keywords, &raw, &hex))
|
||||
return -1;
|
||||
|
||||
/* We expect one or the other, but not both. */
|
||||
if (raw == NULL && hex == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Expected raw or hex.");
|
||||
return -1;
|
||||
}
|
||||
if (raw != NULL && hex != NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Expected raw or hex, not both.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Case 1: raw */
|
||||
if (raw != NULL) {
|
||||
err = PyBytes_AsStringAndSize(raw, &bytes, &len);
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
if (len > GIT_OID_RAWSZ) {
|
||||
PyErr_SetObject(PyExc_ValueError, raw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(self->oid.id, (const unsigned char*)bytes, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Case 2: hex */
|
||||
err = _oid_from_hex(hex, &self->oid);
|
||||
if (err < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Py_hash_t
|
||||
Oid_hash(PyObject *oid)
|
||||
{
|
||||
/* TODO Randomize (use _Py_HashSecret) to avoid collission DoS attacks? */
|
||||
return *(Py_hash_t*) ((Oid*)oid)->oid.id;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
Oid_richcompare(PyObject *o1, PyObject *o2, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
int cmp;
|
||||
|
||||
/* Comparing to something else than an Oid is not supported. */
|
||||
if (!PyObject_TypeCheck(o2, &OidType)) {
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
|
||||
/* Ok go. */
|
||||
cmp = git_oid_cmp(&((Oid*)o1)->oid, &((Oid*)o2)->oid);
|
||||
switch (op) {
|
||||
case Py_LT:
|
||||
res = (cmp <= 0) ? Py_True: Py_False;
|
||||
break;
|
||||
case Py_LE:
|
||||
res = (cmp < 0) ? Py_True: Py_False;
|
||||
break;
|
||||
case Py_EQ:
|
||||
res = (cmp == 0) ? Py_True: Py_False;
|
||||
break;
|
||||
case Py_NE:
|
||||
res = (cmp != 0) ? Py_True: Py_False;
|
||||
break;
|
||||
case Py_GT:
|
||||
res = (cmp > 0) ? Py_True: Py_False;
|
||||
break;
|
||||
case Py_GE:
|
||||
res = (cmp >= 0) ? Py_True: Py_False;
|
||||
break;
|
||||
}
|
||||
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Oid_raw__doc__, "Raw oid.");
|
||||
|
||||
PyObject *
|
||||
Oid_raw__get__(Oid *self)
|
||||
{
|
||||
return PyBytes_FromStringAndSize((const char*)self->oid.id, GIT_OID_RAWSZ);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Oid_hex__doc__, "Hex oid.");
|
||||
|
||||
PyObject *
|
||||
Oid_hex__get__(Oid *self)
|
||||
{
|
||||
return git_oid_to_py_str(&self->oid);
|
||||
}
|
||||
|
||||
PyGetSetDef Oid_getseters[] = {
|
||||
GETTER(Oid, raw),
|
||||
GETTER(Oid, hex),
|
||||
{NULL},
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(Oid__doc__, "Object id.");
|
||||
|
||||
PyTypeObject OidType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.Oid", /* tp_name */
|
||||
sizeof(Oid), /* 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 */
|
||||
(hashfunc)Oid_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
Oid__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
(richcmpfunc)Oid_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Oid_getseters, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)Oid_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
@@ -34,10 +34,8 @@
|
||||
|
||||
int py_str_to_git_oid(PyObject *py_str, git_oid *oid);
|
||||
int py_str_to_git_oid_expand(git_repository *repo, PyObject *py_str,
|
||||
git_oid *oid);
|
||||
git_oid *oid);
|
||||
PyObject* git_oid_to_python(const git_oid *oid);
|
||||
PyObject* git_oid_to_py_str(const git_oid *oid);
|
||||
|
||||
#define git_oid_to_python(id) \
|
||||
PyBytes_FromStringAndSize((const char*)id, GIT_OID_RAWSZ)
|
||||
|
||||
#endif
|
||||
|
@@ -38,6 +38,7 @@
|
||||
extern PyObject *GitError;
|
||||
|
||||
extern PyTypeObject RepositoryType;
|
||||
extern PyTypeObject OidType;
|
||||
extern PyTypeObject ObjectType;
|
||||
extern PyTypeObject CommitType;
|
||||
extern PyTypeObject DiffType;
|
||||
@@ -141,7 +142,7 @@ hashfile(PyObject *self, PyObject *args)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(hash__doc__,
|
||||
@@ -165,7 +166,7 @@ hash(PyObject *self, PyObject *args)
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +194,10 @@ moduleinit(PyObject* m)
|
||||
INIT_TYPE(RepositoryType, NULL, PyType_GenericNew)
|
||||
ADD_TYPE(m, Repository);
|
||||
|
||||
/* Oid */
|
||||
INIT_TYPE(OidType, NULL, PyType_GenericNew)
|
||||
ADD_TYPE(m, Oid);
|
||||
|
||||
/* Objects (make them with the Repository.create_XXX methods). */
|
||||
INIT_TYPE(ObjectType, NULL, NULL)
|
||||
INIT_TYPE(CommitType, &ObjectType, NULL)
|
||||
|
@@ -204,18 +204,17 @@ Reference_target__get__(Reference *self)
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
/* Get the target */
|
||||
if (GIT_REF_OID == git_reference_type(self->reference)) {
|
||||
return git_oid_to_py_str(git_reference_target(self->reference));
|
||||
} else {
|
||||
c_name = git_reference_symbolic_target(self->reference);
|
||||
if (c_name == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "no target available");
|
||||
return NULL;
|
||||
}
|
||||
/* Case 1: Direct */
|
||||
if (GIT_REF_OID == git_reference_type(self->reference))
|
||||
return git_oid_to_python(git_reference_target(self->reference));
|
||||
|
||||
/* Case 2: Symbolic */
|
||||
c_name = git_reference_symbolic_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);
|
||||
}
|
||||
|
||||
@@ -262,21 +261,17 @@ PyDoc_STRVAR(Reference_oid__doc__, "Object id.");
|
||||
PyObject *
|
||||
Reference_oid__get__(Reference *self)
|
||||
{
|
||||
const git_oid *oid;
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
/* Get the oid (only for "direct" references) */
|
||||
oid = git_reference_target(self->reference);
|
||||
if (oid == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"oid is only available if the reference is direct "
|
||||
"(i.e. not symbolic)");
|
||||
return NULL;
|
||||
}
|
||||
/* Case 1: Direct */
|
||||
if (GIT_REF_OID == git_reference_type(self->reference))
|
||||
return git_oid_to_python(git_reference_target(self->reference));
|
||||
|
||||
/* Convert and return it */
|
||||
return git_oid_to_python(oid->id);
|
||||
/* Get the oid (only for "direct" references) */
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"oid is only available if the reference is direct "
|
||||
"(i.e. not symbolic)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
|
@@ -132,10 +132,10 @@ static int
|
||||
Repository_build_as_iter(const git_oid *oid, void *accum)
|
||||
{
|
||||
int err;
|
||||
PyObject *oid_str = git_oid_to_py_str(oid);
|
||||
PyObject *py_oid = git_oid_to_python(oid);
|
||||
|
||||
err = PyList_Append((PyObject*)accum, oid_str);
|
||||
Py_DECREF(oid_str);
|
||||
err = PyList_Append((PyObject*)accum, py_oid);
|
||||
Py_DECREF(py_oid);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -152,11 +152,10 @@ Repository_as_iter(Repository *self)
|
||||
|
||||
err = git_odb_foreach(odb, Repository_build_as_iter, (void*)accum);
|
||||
git_odb_free(odb);
|
||||
if (err == GIT_EUSER) {
|
||||
if (err == GIT_EUSER)
|
||||
return NULL;
|
||||
} else if (err < 0) {
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
return PyObject_GetIter(accum);
|
||||
}
|
||||
@@ -399,7 +398,7 @@ Repository_write(Repository *self, PyObject *args)
|
||||
stream->write(stream, buffer, buflen);
|
||||
err = stream->finalize_write(&oid, stream);
|
||||
stream->free(stream);
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
@@ -574,7 +573,7 @@ Repository_create_blob(Repository *self, PyObject *args)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
@@ -597,7 +596,7 @@ Repository_create_blob_fromfile(Repository *self, PyObject *args)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
@@ -670,7 +669,7 @@ Repository_create_commit(Repository *self, PyObject *args)
|
||||
goto out;
|
||||
}
|
||||
|
||||
py_result = git_oid_to_python(oid.id);
|
||||
py_result = git_oid_to_python(&oid);
|
||||
|
||||
out:
|
||||
free(message);
|
||||
@@ -718,7 +717,7 @@ Repository_create_tag(Repository *self, PyObject *args)
|
||||
git_object_free(target);
|
||||
if (err < 0)
|
||||
return Error_set_oid(err, &oid, len);
|
||||
return git_oid_to_python(oid.id);
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
@@ -1153,7 +1152,7 @@ Repository_create_note(Repository *self, PyObject* args)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(note_id.id);
|
||||
return git_oid_to_python(¬e_id);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -43,7 +43,7 @@ Tag_target__get__(Tag *self)
|
||||
const git_oid *oid;
|
||||
|
||||
oid = git_tag_target_id(self->tag);
|
||||
return git_oid_to_python(oid->id);
|
||||
return git_oid_to_python(oid);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -74,7 +74,7 @@ TreeEntry_oid__get__(TreeEntry *self)
|
||||
const git_oid *oid;
|
||||
|
||||
oid = git_tree_entry_id(self->entry);
|
||||
return git_oid_to_python(oid->id);
|
||||
return git_oid_to_python(oid);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -46,6 +46,12 @@ typedef struct {
|
||||
} Repository;
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
git_oid oid;
|
||||
} Oid;
|
||||
|
||||
|
||||
#define SIMPLE_TYPE(_name, _ptr_type, _ptr_name) \
|
||||
typedef struct {\
|
||||
PyObject_HEAD\
|
||||
|
@@ -54,6 +54,11 @@
|
||||
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
|
||||
#endif
|
||||
|
||||
#ifndef Py_hash_t
|
||||
#define Py_hash_t long
|
||||
#endif
|
||||
|
||||
|
||||
#define CHECK_REFERENCE(self)\
|
||||
if (self->reference == NULL) {\
|
||||
PyErr_SetString(GitError, "deleted reference");\
|
||||
|
@@ -35,9 +35,9 @@ import sys
|
||||
import unittest
|
||||
|
||||
|
||||
names = ['blob', 'commit', 'config', 'diff', 'index', 'refs', 'remote',
|
||||
'repository', 'revwalk', 'signature', 'status', 'tag', 'tree',
|
||||
'treebuilder', 'note']
|
||||
names = ['blob', 'commit', 'config', 'diff', 'index', 'note', 'oid', 'refs',
|
||||
'remote', 'repository', 'revwalk', 'signature', 'status', 'tag',
|
||||
'tree', 'treebuilder']
|
||||
|
||||
def test_suite():
|
||||
# Sometimes importing pygit2 fails, we try this first to get an
|
||||
|
@@ -49,7 +49,7 @@ class BlobTest(utils.RepoTestCase):
|
||||
def test_read_blob(self):
|
||||
blob = self.repo[BLOB_SHA]
|
||||
self.assertEqual(blob.hex, BLOB_SHA)
|
||||
sha = utils.oid_to_hex(blob.oid)
|
||||
sha = blob.oid.hex
|
||||
self.assertEqual(sha, BLOB_SHA)
|
||||
self.assertTrue(isinstance(blob, pygit2.Blob))
|
||||
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
|
||||
@@ -66,9 +66,8 @@ class BlobTest(utils.RepoTestCase):
|
||||
|
||||
self.assertEqual(blob_oid, blob.oid)
|
||||
self.assertEqual(
|
||||
utils.gen_blob_sha1(BLOB_NEW_CONTENT),
|
||||
utils.oid_to_hex(blob_oid)
|
||||
)
|
||||
utils.gen_blob_sha1(BLOB_NEW_CONTENT),
|
||||
blob_oid.hex)
|
||||
|
||||
self.assertEqual(BLOB_NEW_CONTENT, blob.data)
|
||||
self.assertEqual(len(BLOB_NEW_CONTENT), blob.size)
|
||||
@@ -84,9 +83,8 @@ class BlobTest(utils.RepoTestCase):
|
||||
|
||||
self.assertEqual(blob_oid, blob.oid)
|
||||
self.assertEqual(
|
||||
utils.gen_blob_sha1(BLOB_FILE_CONTENT),
|
||||
utils.oid_to_hex(blob_oid)
|
||||
)
|
||||
utils.gen_blob_sha1(BLOB_FILE_CONTENT),
|
||||
blob_oid.hex)
|
||||
|
||||
self.assertEqual(BLOB_FILE_CONTENT, blob.data)
|
||||
self.assertEqual(len(BLOB_FILE_CONTENT), blob.size)
|
||||
|
@@ -98,8 +98,7 @@ class IndexTest(utils.RepoTestCase):
|
||||
self.assertEqual(len(index), 1)
|
||||
# Test read-write returns the same oid
|
||||
oid = index.write_tree()
|
||||
oid = utils.oid_to_hex(oid)
|
||||
self.assertEqual(oid, tree_oid)
|
||||
self.assertEqual(oid.hex, tree_oid)
|
||||
# Test the index is only modified in memory
|
||||
index.read()
|
||||
self.assertEqual(len(index), 2)
|
||||
@@ -107,8 +106,7 @@ class IndexTest(utils.RepoTestCase):
|
||||
|
||||
def test_write_tree(self):
|
||||
oid = self.repo.index.write_tree()
|
||||
sha = utils.oid_to_hex(oid)
|
||||
self.assertEqual(sha, 'fd937514cb799514d4b81bb24c5fcfeb6472b245')
|
||||
self.assertEqual(oid.hex, 'fd937514cb799514d4b81bb24c5fcfeb6472b245')
|
||||
|
||||
def test_iter(self):
|
||||
index = self.repo.index
|
||||
|
@@ -37,19 +37,20 @@ from . import utils
|
||||
NOTE = ('6c8980ba963cad8b25a9bcaf68d4023ee57370d8', 'note message')
|
||||
|
||||
NOTES = [
|
||||
('ab533997b80705767be3dae8cbb06a0740809f79', 'First Note - HEAD\n',
|
||||
'784855caf26449a1914d2cf62d12b9374d76ae78'),
|
||||
('d879714d880671ed84f8aaed8b27fca23ba01f27', 'Second Note - HEAD~1\n',
|
||||
'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87')
|
||||
]
|
||||
('ab533997b80705767be3dae8cbb06a0740809f79', 'First Note - HEAD\n',
|
||||
'784855caf26449a1914d2cf62d12b9374d76ae78'),
|
||||
('d879714d880671ed84f8aaed8b27fca23ba01f27', 'Second Note - HEAD~1\n',
|
||||
'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87')
|
||||
]
|
||||
|
||||
class NotesTest(utils.BareRepoTestCase):
|
||||
|
||||
|
||||
def test_create_note(self):
|
||||
annotated_id = self.repo.revparse_single('HEAD~3').hex
|
||||
author = committer = Signature('Foo bar', 'foo@bar.com', 12346, 0)
|
||||
note_id = self.repo.create_note(NOTE[1], author, committer, annotated_id)
|
||||
self.assertEqual(NOTE[0], utils.oid_to_hex(note_id))
|
||||
note_id = self.repo.create_note(NOTE[1], author, committer,
|
||||
annotated_id)
|
||||
self.assertEqual(NOTE[0], note_id.hex)
|
||||
|
||||
# check the note blob
|
||||
self.assertEqual(NOTE[1].encode(), self.repo[note_id].data)
|
||||
@@ -57,22 +58,23 @@ class NotesTest(utils.BareRepoTestCase):
|
||||
def test_lookup_note(self):
|
||||
annotated_id = self.repo.head.hex
|
||||
note = self.repo.lookup_note(annotated_id)
|
||||
self.assertEqual(NOTES[0][0], note.oid)
|
||||
self.assertEqual(NOTES[0][0], note.oid.hex)
|
||||
self.assertEqual(NOTES[0][1], note.message)
|
||||
|
||||
def test_remove_note(self):
|
||||
note = self.repo.lookup_note(self.repo.head.hex)
|
||||
author = committer = Signature('Foo bar', 'foo@bar.com', 12346, 0)
|
||||
note.remove(author, committer)
|
||||
self.assertRaises(KeyError, lambda: self.repo.lookup_note(self.repo.head.hex))
|
||||
self.assertRaises(KeyError, self.repo.lookup_note, self.repo.head.hex)
|
||||
|
||||
def test_iterate_notes(self):
|
||||
for i, note in enumerate(self.repo.notes()):
|
||||
entry = (note.oid, note.message, note.annotated_id)
|
||||
self.assertEqual(NOTES[i],entry)
|
||||
entry = (note.oid.hex, note.message, note.annotated_id)
|
||||
self.assertEqual(NOTES[i], entry)
|
||||
|
||||
def test_iterate_non_existing_ref(self):
|
||||
self.assertRaises(KeyError, lambda: self.repo.notes("refs/notes/bad_ref"))
|
||||
self.assertRaises(KeyError, self.repo.notes, "refs/notes/bad_ref")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
109
test/test_oid.py
Normal file
109
test/test_oid.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2013 The pygit2 contributors
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Tests for Object ids."""
|
||||
|
||||
# Import from the future
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Import from the Standard Library
|
||||
from binascii import unhexlify
|
||||
from sys import version_info
|
||||
import unittest
|
||||
|
||||
# Import from pygit2
|
||||
from pygit2 import Oid
|
||||
from . import utils
|
||||
|
||||
|
||||
HEX = "15b648aec6ed045b5ca6f57f8b7831a8b4757298"
|
||||
RAW = unhexlify(HEX.encode('ascii'))
|
||||
|
||||
class OidTest(utils.BareRepoTestCase):
|
||||
|
||||
def test_raw(self):
|
||||
oid = Oid(raw=RAW)
|
||||
self.assertEqual(oid.raw, RAW)
|
||||
self.assertEqual(oid.hex, HEX)
|
||||
|
||||
def test_hex(self):
|
||||
oid = Oid(hex=HEX)
|
||||
self.assertEqual(oid.raw, RAW)
|
||||
self.assertEqual(oid.hex, HEX)
|
||||
|
||||
def test_hex_bytes(self):
|
||||
if version_info[0] == 2:
|
||||
hex = bytes(HEX)
|
||||
oid = Oid(hex=hex)
|
||||
self.assertEqual(oid.raw, RAW)
|
||||
self.assertEqual(oid.hex, HEX)
|
||||
else:
|
||||
hex = bytes(HEX, "ascii")
|
||||
self.assertRaises(TypeError, Oid, hex=hex)
|
||||
|
||||
def test_none(self):
|
||||
self.assertRaises(ValueError, Oid)
|
||||
|
||||
def test_both(self):
|
||||
self.assertRaises(ValueError, Oid, raw=RAW, hex=HEX)
|
||||
|
||||
def test_long(self):
|
||||
self.assertRaises(ValueError, Oid, raw=RAW + b'a')
|
||||
self.assertRaises(ValueError, Oid, hex=HEX + 'a')
|
||||
|
||||
def test_cmp(self):
|
||||
oid1 = Oid(raw=RAW)
|
||||
|
||||
# Equal
|
||||
oid2 = Oid(hex=HEX)
|
||||
self.assertEqual(oid1, oid2)
|
||||
|
||||
# Not equal
|
||||
oid2 = Oid(hex="15b648aec6ed045b5ca6f57f8b7831a8b4757299")
|
||||
self.assertNotEqual(oid1, oid2)
|
||||
|
||||
# Other
|
||||
self.assertTrue(oid1 < oid2)
|
||||
self.assertTrue(oid1 <= oid2)
|
||||
self.assertFalse(oid1 == oid2)
|
||||
self.assertFalse(oid1 > oid2)
|
||||
self.assertFalse(oid1 >= oid2)
|
||||
|
||||
def test_hash(self):
|
||||
s = set()
|
||||
s.add(Oid(raw=RAW))
|
||||
s.add(Oid(hex=HEX))
|
||||
self.assertEqual(len(s), 1)
|
||||
|
||||
s.add(Oid(hex="0000000000000000000000000000000000000000"))
|
||||
s.add(Oid(hex="0000000000000000000000000000000000000001"))
|
||||
self.assertEqual(len(s), 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@@ -176,7 +176,7 @@ class ReferencesTest(utils.RepoTestCase):
|
||||
self.assertTrue('refs/tags/version1' in refs)
|
||||
reference = self.repo.lookup_reference('refs/tags/version1')
|
||||
self.assertEqual(reference.hex, LAST_COMMIT)
|
||||
self.assertEqual(reference.target, LAST_COMMIT)
|
||||
self.assertEqual(reference.target.hex, LAST_COMMIT)
|
||||
|
||||
# try to create existing reference
|
||||
self.assertRaises(ValueError, self.repo.create_reference,
|
||||
|
@@ -41,14 +41,16 @@ from os.path import join, realpath
|
||||
# Import from pygit2
|
||||
from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT
|
||||
from pygit2 import init_repository, discover_repository, Reference, hashfile
|
||||
from pygit2 import Oid
|
||||
import pygit2
|
||||
from . import utils
|
||||
|
||||
|
||||
HEAD_SHA = '784855caf26449a1914d2cf62d12b9374d76ae78'
|
||||
PARENT_SHA = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87' # HEAD^
|
||||
A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
|
||||
A_BIN_SHA = binascii.unhexlify(A_HEX_SHA.encode('ascii'))
|
||||
BLOB_HEX = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
|
||||
BLOB_RAW = binascii.unhexlify(BLOB_HEX.encode('ascii'))
|
||||
BLOB_OID = Oid(raw=BLOB_RAW)
|
||||
|
||||
|
||||
class RepositoryTest(utils.BareRepoTestCase):
|
||||
@@ -70,15 +72,15 @@ class RepositoryTest(utils.BareRepoTestCase):
|
||||
self.assertRaises(TypeError, self.repo.read, 123)
|
||||
self.assertRaisesWithArg(KeyError, '1' * 40, self.repo.read, '1' * 40)
|
||||
|
||||
ab = self.repo.read(A_BIN_SHA)
|
||||
a = self.repo.read(A_HEX_SHA)
|
||||
ab = self.repo.read(BLOB_OID)
|
||||
a = self.repo.read(BLOB_HEX)
|
||||
self.assertEqual(ab, a)
|
||||
self.assertEqual((GIT_OBJ_BLOB, b'a contents\n'), a)
|
||||
|
||||
a2 = self.repo.read('7f129fd57e31e935c6d60a0c794efe4e6927664b')
|
||||
self.assertEqual((GIT_OBJ_BLOB, b'a contents 2\n'), a2)
|
||||
|
||||
a_hex_prefix = A_HEX_SHA[:4]
|
||||
a_hex_prefix = BLOB_HEX[:4]
|
||||
a3 = self.repo.read(a_hex_prefix)
|
||||
self.assertEqual((GIT_OBJ_BLOB, b'a contents\n'), a3)
|
||||
|
||||
@@ -88,34 +90,33 @@ class RepositoryTest(utils.BareRepoTestCase):
|
||||
self.assertRaises(ValueError, self.repo.write, GIT_OBJ_ANY, data)
|
||||
|
||||
oid = self.repo.write(GIT_OBJ_BLOB, data)
|
||||
self.assertEqual(type(oid), bytes)
|
||||
self.assertEqual(len(oid), 20)
|
||||
self.assertEqual(type(oid), Oid)
|
||||
|
||||
def test_contains(self):
|
||||
self.assertRaises(TypeError, lambda: 123 in self.repo)
|
||||
self.assertTrue(A_BIN_SHA in self.repo)
|
||||
self.assertTrue(A_BIN_SHA[:10] in self.repo)
|
||||
self.assertTrue(A_HEX_SHA in self.repo)
|
||||
self.assertTrue(A_HEX_SHA[:10] in self.repo)
|
||||
self.assertTrue(BLOB_OID in self.repo)
|
||||
self.assertTrue(BLOB_HEX in self.repo)
|
||||
self.assertTrue(BLOB_HEX[:10] in self.repo)
|
||||
self.assertFalse('a' * 40 in self.repo)
|
||||
self.assertFalse('a' * 20 in self.repo)
|
||||
|
||||
def test_iterable(self):
|
||||
l = [ obj for obj in self.repo ]
|
||||
self.assertTrue(A_HEX_SHA in l)
|
||||
oid = Oid(hex=BLOB_HEX)
|
||||
self.assertTrue(oid in l)
|
||||
|
||||
def test_lookup_blob(self):
|
||||
self.assertRaises(TypeError, lambda: self.repo[123])
|
||||
self.assertEqual(self.repo[A_BIN_SHA].hex, A_HEX_SHA)
|
||||
a = self.repo[A_HEX_SHA]
|
||||
self.assertEqual(self.repo[BLOB_OID].hex, BLOB_HEX)
|
||||
a = self.repo[BLOB_HEX]
|
||||
self.assertEqual(b'a contents\n', a.read_raw())
|
||||
self.assertEqual(A_HEX_SHA, a.hex)
|
||||
self.assertEqual(BLOB_HEX, a.hex)
|
||||
self.assertEqual(GIT_OBJ_BLOB, a.type)
|
||||
|
||||
def test_lookup_blob_prefix(self):
|
||||
a = self.repo[A_HEX_SHA[:5]]
|
||||
a = self.repo[BLOB_HEX[:5]]
|
||||
self.assertEqual(b'a contents\n', a.read_raw())
|
||||
self.assertEqual(A_HEX_SHA, a.hex)
|
||||
self.assertEqual(BLOB_HEX, a.hex)
|
||||
self.assertEqual(GIT_OBJ_BLOB, a.type)
|
||||
|
||||
def test_lookup_commit(self):
|
||||
@@ -230,16 +231,18 @@ class RepositoryTest_II(utils.RepoTestCase):
|
||||
self.repo.checkout(pygit2.GIT_CHECKOUT_FORCE, head=True)
|
||||
self.assertTrue('bye.txt' not in self.repo.status())
|
||||
|
||||
|
||||
class NewRepositoryTest(utils.NoRepoTestCase):
|
||||
|
||||
def test_new_repo(self):
|
||||
repo = init_repository(self._temp_dir, False)
|
||||
|
||||
oid = repo.write(GIT_OBJ_BLOB, "Test")
|
||||
self.assertEqual(type(oid), bytes)
|
||||
self.assertEqual(len(oid), 20)
|
||||
self.assertEqual(type(oid), Oid)
|
||||
|
||||
assert os.path.exists(os.path.join(self._temp_dir, '.git'))
|
||||
|
||||
|
||||
class InitRepositoryTest(utils.NoRepoTestCase):
|
||||
# under the assumption that repo.is_bare works
|
||||
|
||||
|
@@ -72,7 +72,7 @@ class TagTest(utils.BareRepoTestCase):
|
||||
|
||||
self.assertEqual('3ee44658fd11660e828dfc96b9b5c5f38d5b49bb', tag.hex)
|
||||
self.assertEqual(name, tag.name)
|
||||
self.assertEqual(target, utils.oid_to_hex(tag.target))
|
||||
self.assertEqual(target, tag.target.hex)
|
||||
self.assertEqualSignature(tagger, tag.tagger)
|
||||
self.assertEqual(message, tag.message)
|
||||
self.assertEqual(name, self.repo[tag.hex].name)
|
||||
|
@@ -47,8 +47,6 @@ def force_rm_handle(remove_path, path, excinfo):
|
||||
)
|
||||
remove_path(path)
|
||||
|
||||
def oid_to_hex(oid):
|
||||
return b2a_hex(oid).decode('ascii')
|
||||
|
||||
def gen_blob_sha1(data):
|
||||
# http://stackoverflow.com/questions/552659/assigning-git-sha1s-without-git
|
||||
@@ -58,6 +56,7 @@ def gen_blob_sha1(data):
|
||||
|
||||
return m.hexdigest()
|
||||
|
||||
|
||||
def rmtree(path):
|
||||
"""In Windows a read-only file cannot be removed, and shutil.rmtree fails.
|
||||
So we implement our own version of rmtree to address this issue.
|
||||
|
Reference in New Issue
Block a user