Skip to content

Commit 8215bc9

Browse files
committed
TreeEntry: add .blob and .tree properties
Saves doing another `repo[tree_entry.id]` lookup Tree navigation: `blob = (tree / 'path' / 'file').blob`
1 parent 23e603a commit 8215bc9

File tree

3 files changed

+72
-13
lines changed

3 files changed

+72
-13
lines changed

src/tree.c

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "error.h"
3232
#include "utils.h"
3333
#include "repository.h"
34+
#include "object.h"
3435
#include "oid.h"
3536
#include "tree.h"
3637
#include "diff.h"
@@ -177,25 +178,14 @@ TreeEntry_hex__get__(TreeEntry *self)
177178
return git_oid_to_py_str(git_tree_entry_id(self->entry));
178179
}
179180

180-
PyObject *
181-
TreeEntry_repr(TreeEntry *self)
182-
{
183-
char str[GIT_OID_HEXSZ + 1] = { 0 };
184-
const char *typename;
185-
186-
typename = git_object_type2string(git_tree_entry_type(self->entry));
187-
git_oid_fmt(str, git_tree_entry_id(self->entry));
188-
return PyString_FromFormat("pygit2.TreeEntry('%s', %s, %s)", git_tree_entry_name(self->entry), typename, str);
189-
}
190-
191181
git_tree *
192182
treeentry_to_subtree(TreeEntry* self)
193183
{
194184
Repository *py_repo;
195185
git_tree *subtree = NULL;
196186

197187
if (git_tree_entry_type(self->entry) != GIT_OBJ_TREE) {
198-
PyErr_SetString(PyExc_TypeError, "Only supported for trees");
188+
PyErr_SetString(PyExc_TypeError, "Only for trees");
199189
return NULL;
200190
}
201191

@@ -214,6 +204,62 @@ treeentry_to_subtree(TreeEntry* self)
214204
return subtree;
215205
}
216206

207+
PyObject *
208+
treeentry_to_object(TreeEntry* self)
209+
{
210+
Repository *py_repo;
211+
git_object *obj= NULL;
212+
213+
if (self->repo == NULL) {
214+
PyErr_SetString(PyExc_ValueError, "No repository associated with this TreeEntry");
215+
return NULL;
216+
}
217+
py_repo = self->repo;
218+
219+
int err = git_tree_entry_to_object(&obj, py_repo->repo, self->entry);
220+
if (err < 0) {
221+
Error_set(err);
222+
return NULL;
223+
}
224+
225+
return wrap_object(obj, py_repo);
226+
}
227+
PyDoc_STRVAR(TreeEntry_tree__doc__, "Subtree");
228+
229+
PyObject *
230+
TreeEntry_tree__get__(TreeEntry *self)
231+
{
232+
git_tree* subtree = treeentry_to_subtree(self);
233+
if (subtree == NULL)
234+
return NULL;
235+
236+
return wrap_object((git_object*)subtree, self->repo);
237+
}
238+
239+
PyDoc_STRVAR(TreeEntry_blob__doc__, "Blob");
240+
241+
PyObject *
242+
TreeEntry_blob__get__(TreeEntry *self)
243+
{
244+
if (git_tree_entry_type(self->entry) != GIT_OBJ_BLOB) {
245+
PyErr_SetString(PyExc_TypeError, "Only for blobs");
246+
return NULL;
247+
}
248+
249+
return treeentry_to_object(self);
250+
}
251+
252+
PyObject *
253+
TreeEntry_repr(TreeEntry *self)
254+
{
255+
char str[GIT_OID_HEXSZ + 1] = { 0 };
256+
const char *typename;
257+
258+
typename = git_object_type2string(git_tree_entry_type(self->entry));
259+
git_oid_fmt(str, git_tree_entry_id(self->entry));
260+
return PyString_FromFormat("pygit2.TreeEntry('%s', %s, %s)", git_tree_entry_name(self->entry), typename, str);
261+
}
262+
217263
int
218264
TreeEntry_contains(TreeEntry *self, PyObject *py_name)
219265
{
@@ -295,6 +341,8 @@ PyGetSetDef TreeEntry_getseters[] = {
295341
GETTER(TreeEntry, id),
296342
GETTER(TreeEntry, hex),
297343
GETTER(TreeEntry, type),
344+
GETTER(TreeEntry, blob),
345+
GETTER(TreeEntry, tree),
298346
{NULL}
299347
};
300348

src/tree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ PyObject* TreeEntry_get_filemode(TreeEntry *self);
3838
PyObject* TreeEntry_get_name(TreeEntry *self);
3939
PyObject* TreeEntry_get_oid(TreeEntry *self);
4040
PyObject* TreeEntry_get_hex(TreeEntry *self);
41+
PyObject* TreeEntry_get_blob(TreeEntry *self);
42+
PyObject* TreeEntry_get_tree(TreeEntry *self);
4143

4244
TreeEntry* tree_getitem_by_index(const git_tree *tree, Repository *repo, PyObject *py_index);
4345
TreeEntry* tree_getitem_by_path(const git_tree *tree, Repository *repo, PyObject *py_path);

test/test_tree.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ def test_read_tree(self):
8383
self.assertRaisesWithArg(KeyError, 'ab/cd', lambda: tree['ab/cd'])
8484
self.assertRaisesWithArg(KeyError, 'ab/cd', lambda: tree / 'ab/cd')
8585
self.assertRaisesWithArg(KeyError, 'ab', lambda: tree / 'c' / 'ab')
86-
self.assertRaisesWithArg(TypeError, 'Only supported for trees', lambda: tree / 'a' / 'cd')
86+
self.assertRaisesWithArg(TypeError, 'Only for trees', lambda: tree / 'a' / 'cd')
87+
88+
self.assertRaisesWithArg(TypeError, 'Only for trees', lambda: (tree / 'c' / 'd').tree)
89+
self.assertRaisesWithArg(TypeError, 'Only for blobs', lambda: (tree / 'c').blob)
8790

8891
def test_equality(self):
8992
tree_a = self.repo['18e2d2e9db075f9eb43bcb2daa65a2867d29a15e']
@@ -113,6 +116,8 @@ def test_read_subtree(self):
113116
sha = '297efb891a47de80be0cfe9c639e4b8c9b450989'
114117
self.assertTreeEntryEqual(subtree[0], sha, 'd', 0o0100644)
115118

119+
subtree_entry = (tree / 'c')
120+
assert subtree_entry.tree == self.repo[subtree_entry.id]
116121

117122
def test_new_tree(self):
118123
repo = self.repo
@@ -154,6 +159,10 @@ def test_new_tree(self):
154159
assert y.type == 'blob'
155160
assert z.type == 'tree'
156161

162+
assert x.blob == repo[x.id]
163+
assert y.blob == repo[y.id]
164+
assert z.tree == repo[z.id]
165+
157166

158167
def test_modify_tree(self):
159168
tree = self.repo[TREE_SHA]

0 commit comments

Comments
 (0)