Merge branch 'oid'

This commit is contained in:
J. David Ibáñez
2013-04-20 22:43:33 +02:00
22 changed files with 486 additions and 120 deletions

View File

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

View File

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

View File

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

View File

@@ -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
View File

@@ -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 */
};

View File

@@ -35,9 +35,7 @@
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);
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

View File

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

View File

@@ -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 {
/* 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,23 +261,19 @@ PyDoc_STRVAR(Reference_oid__doc__, "Object id.");
PyObject *
Reference_oid__get__(Reference *self)
{
const git_oid *oid;
CHECK_REFERENCE(self);
/* Case 1: Direct */
if (GIT_REF_OID == git_reference_type(self->reference))
return git_oid_to_python(git_reference_target(self->reference));
/* 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;
}
/* Convert and return it */
return git_oid_to_python(oid->id);
}
int
Reference_oid__set__(Reference *self, PyObject *py_hex)
{

View File

@@ -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(&note_id);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
@@ -67,8 +67,7 @@ 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)
)
blob_oid.hex)
self.assertEqual(BLOB_NEW_CONTENT, blob.data)
self.assertEqual(len(BLOB_NEW_CONTENT), blob.size)
@@ -85,8 +84,7 @@ 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)
)
blob_oid.hex)
self.assertEqual(BLOB_FILE_CONTENT, blob.data)
self.assertEqual(len(BLOB_FILE_CONTENT), blob.size)

View File

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

View File

@@ -48,8 +48,9 @@ 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)
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
View 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()

View File

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

View File

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

View File

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

View File

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