From 404645042be0c131a5736c1695b70f9bcaf32558 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 19 Feb 2015 14:11:20 +0100 Subject: [PATCH 1/5] Add Submodule type. --- docs/index.rst | 1 + docs/submodule.rst | 17 +++++ pygit2/submodule.py | 60 +++++++++++++++ src/pygit2.c | 7 ++ src/repository.c | 76 +++++++++++++++++++ src/repository.h | 2 + src/submodule.c | 178 ++++++++++++++++++++++++++++++++++++++++++++ src/submodule.h | 38 ++++++++++ src/types.h | 7 ++ 9 files changed, 386 insertions(+) create mode 100644 docs/submodule.rst create mode 100644 pygit2/submodule.py create mode 100644 src/submodule.c create mode 100644 src/submodule.h diff --git a/docs/index.rst b/docs/index.rst index 156f0ac..f314911 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -45,6 +45,7 @@ Usage guide: merge config remotes + submodule blame settings features diff --git a/docs/submodule.rst b/docs/submodule.rst new file mode 100644 index 0000000..e2a11ed --- /dev/null +++ b/docs/submodule.rst @@ -0,0 +1,17 @@ +********************************************************************** +The submodule +********************************************************************** + +A submodule is a foreign repository that is embedded within a +dedicated subdirectory of the repositories tree. + +.. automethod:: pygit2.Repository.lookup_submodule +.. automethod:: pygit2.Repository.listall_submodules + +The Submodule type +==================== + +.. autoattribute:: pygit2.Submodule.name +.. autoattribute:: pygit2.Submodule.path +.. autoattribute:: pygit2.Submodule.url +.. automethod:: pygit2.Submodule.open diff --git a/pygit2/submodule.py b/pygit2/submodule.py new file mode 100644 index 0000000..4b1ac10 --- /dev/null +++ b/pygit2/submodule.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2010-2015 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. + +# Import from the future +from __future__ import absolute_import + +# Import from pygit2 +from _pygit2 import Submodule as _Submodule + +from .ffi import ffi + + +class Submodule(_Submodule): + + def __init__(self, *args, **kwargs): + super(Submodule, self).__init__(*args, **kwargs) + self._common_init() + + @classmethod + def _from_c(cls, ptr, owned): + cptr = ffi.new('git_submodule **') + cptr[0] = ptr + submodule = cls.__new__(cls) + super(cls, submodule)._from_c(bytes(ffi.buffer(cptr)[:]), owned) + submodule._common_init() + return submodule + + def _common_init(self): + # Get the pointer as the contents of a buffer and store it for + # later access + submodule_cptr = ffi.new('git_submodule **') + ffi.buffer(submodule_cptr)[:] = self._pointer[:] + self._submodule = submodule_cptr[0] + + def __repr__(self): + return "pygit2.Submodule(%r)" % self.name diff --git a/src/pygit2.c b/src/pygit2.c index 5a661b8..f116725 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -42,6 +42,7 @@ extern PyTypeObject RepositoryType; extern PyTypeObject OidType; extern PyTypeObject ObjectType; extern PyTypeObject CommitType; +extern PyTypeObject SubmoduleType; extern PyTypeObject DiffType; extern PyTypeObject DiffIterType; extern PyTypeObject DiffDeltaType; @@ -219,6 +220,12 @@ moduleinit(PyObject* m) ADD_CONSTANT_INT(m, GIT_FILEMODE_LINK) ADD_CONSTANT_INT(m, GIT_FILEMODE_COMMIT) + /* + * Submodules + */ + INIT_TYPE(SubmoduleType, NULL, NULL); + ADD_TYPE(m, Submodule); + /* * Log */ diff --git a/src/repository.c b/src/repository.c index bcedf5d..b142c91 100644 --- a/src/repository.c +++ b/src/repository.c @@ -37,6 +37,7 @@ #include "repository.h" #include "branch.h" #include "signature.h" +#include "submodule.h" #include extern PyObject *GitError; @@ -70,6 +71,20 @@ int_to_loose_object_type(int type_id) } } +PyObject * +wrap_repository(git_repository *c_repo) +{ + Repository *py_repo = PyObject_GC_New(Repository, &RepositoryType); + + if (py_repo) { + py_repo->repo = c_repo; + py_repo->config = NULL; + py_repo->index = NULL; + } + + return (PyObject *)py_repo; +} + int Repository_init(Repository *self, PyObject *args, PyObject *kwds) { @@ -1084,6 +1099,65 @@ error: return NULL; } +PyDoc_STRVAR(Repository_lookup_submodule__doc__, + "lookup_submodule(path) -> Submodule\n" + "\n" + "Lookup a submodule by its path in a repository."); + +PyObject * +Repository_lookup_submodule(Repository *self, PyObject *py_path) +{ + git_submodule *c_submodule; + char *c_name; + int err; + + c_name = py_path_to_c_str(py_path); + if (c_name == NULL) + return NULL; + + err = git_submodule_lookup(&c_submodule, self->repo, c_name); + if (err < 0) { + PyObject *err_obj = Error_set_str(err, c_name); + free(c_name); + return err_obj; + } + free(c_name); + + return wrap_submodule(self, c_submodule); +} + +PyDoc_STRVAR(Repository_listall_submodules__doc__, + "listall_submodules() -> [str, ...]\n" + "\n" + "Return a list with all submodule paths in the repository.\n"); + +static int foreach_path_cb(git_submodule *submodule, const char *name, void *payload) +{ + PyObject *list = (PyObject *)payload; + PyObject *path = to_unicode(git_submodule_path(submodule), NULL, NULL); + + return PyList_Append(list, path); +} + +PyObject * +Repository_listall_submodules(Repository *self, PyObject *args) +{ + int err; + PyObject *list; + + list = PyList_New(0); + if (list == NULL) + return NULL; + + err = git_submodule_foreach(self->repo, foreach_path_cb, list); + if (err != 0) { + Py_DECREF(list); + return Py_None; + } + + return list; +} + PyDoc_STRVAR(Repository_lookup_reference__doc__, "lookup_reference(name) -> Reference\n" @@ -1508,6 +1582,8 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, create_reference_direct, METH_VARARGS), METHOD(Repository, create_reference_symbolic, METH_VARARGS), METHOD(Repository, listall_references, METH_NOARGS), + METHOD(Repository, lookup_submodule, METH_O), + METHOD(Repository, listall_submodules, METH_NOARGS), METHOD(Repository, lookup_reference, METH_O), METHOD(Repository, revparse_single, METH_O), METHOD(Repository, status, METH_NOARGS), diff --git a/src/repository.h b/src/repository.h index b69ae22..3f6947e 100644 --- a/src/repository.h +++ b/src/repository.h @@ -33,6 +33,8 @@ #include #include "types.h" +PyObject *wrap_repository(git_repository *c_repo); + int Repository_init(Repository *self, PyObject *args, PyObject *kwds); int Repository_traverse(Repository *self, visitproc visit, void *arg); int Repository_clear(Repository *self); diff --git a/src/submodule.c b/src/submodule.c new file mode 100644 index 0000000..1dbed33 --- /dev/null +++ b/src/submodule.c @@ -0,0 +1,178 @@ +/* + * Copyright 2010-2015 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. + */ + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "error.h" +#include "utils.h" +#include "types.h" +#include "submodule.h" +#include "repository.h" + +PyTypeObject SubmoduleType; + +PyDoc_STRVAR(Submodule_open__doc__, + "open() -> Repository\n" + "\n" + "Open the submodule as repository."); + +PyObject * +Submodule_open(Submodule *self, PyObject *args) +{ + int err; + git_repository *repo; + + err = git_submodule_open(&repo, self->submodule); + if (err < 0) + return Error_set_str(err, giterr_last()->message); + + return wrap_repository(repo); +} + +PyDoc_STRVAR(Submodule_name__doc__, + "Gets name of the submodule\n"); + +PyObject * +Submodule_name__get__(Submodule *self) +{ + return to_unicode(git_submodule_name(self->submodule), NULL, NULL); +} + +PyDoc_STRVAR(Submodule_path__doc__, + "Gets path of the submodule\n"); + +PyObject * +Submodule_path__get__(Submodule *self) +{ + return to_unicode(git_submodule_path(self->submodule), NULL, NULL); +} + +PyDoc_STRVAR(Submodule_url__doc__, + "Gets URL of the submodule\n"); + +PyObject * +Submodule_url__get__(Submodule *self) +{ + const char *url = git_submodule_url(self->submodule); + if (url == NULL) + return Py_None; + return to_unicode(url, NULL, NULL); +} + +PyDoc_STRVAR(Submodule_branch__doc__, + "Gets branch of the submodule\n"); + +PyObject * +Submodule_branch__get__(Submodule *self) +{ + const char *branch = git_submodule_branch(self->submodule); + if (branch == NULL) + return Py_None; + return to_unicode(branch, NULL, NULL); +} + +static void +Submodule_dealloc(Submodule *self) +{ + Py_CLEAR(self->repo); + git_submodule_free(self->submodule); + PyObject_Del(self); +} + +PyMethodDef Submodule_methods[] = { + METHOD(Submodule, open, METH_NOARGS), + {NULL} +}; + +PyGetSetDef Submodule_getseters[] = { + GETTER(Submodule, name), + GETTER(Submodule, path), + GETTER(Submodule, url), + GETTER(Submodule, branch), + {NULL} +}; + +PyDoc_STRVAR(Submodule__doc__, "Submodule object."); + +PyTypeObject SubmoduleType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.Submodule", /* tp_name */ + sizeof(Submodule), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Submodule_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 */ + Submodule__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Submodule_methods, /* tp_methods */ + 0, /* tp_members */ + Submodule_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 */ +}; + +PyObject * +wrap_submodule(Repository *repo, git_submodule *c_submodule) +{ + Submodule *py_submodule = NULL; + + py_submodule = PyObject_New(Submodule, &SubmoduleType); + if (py_submodule) { + py_submodule->submodule = c_submodule; + if (repo) { + py_submodule->repo = repo; + Py_INCREF(repo); + } + } + + return (PyObject *)py_submodule; +} diff --git a/src/submodule.h b/src/submodule.h new file mode 100644 index 0000000..07a9f3b --- /dev/null +++ b/src/submodule.h @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2015 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. + */ + +#ifndef INCLUDE_pygit2_submodule_h +#define INCLUDE_pygit2_submodule_h + +#define PY_SSIZE_T_CLEAN +#include +#include + +PyObject *wrap_submodule(Repository* repo, git_submodule *submodule); + +#endif + diff --git a/src/types.h b/src/types.h index 49c62e0..848cf8d 100644 --- a/src/types.h +++ b/src/types.h @@ -75,6 +75,13 @@ SIMPLE_TYPE(Tree, git_tree, tree) SIMPLE_TYPE(Blob, git_blob, blob) SIMPLE_TYPE(Tag, git_tag, tag) +/* git_submodule */ +typedef struct { + PyObject_HEAD + Repository *repo; + git_submodule *submodule; +} Submodule; + /* git_note */ typedef struct { PyObject_HEAD From 86c51eadbfca6a32604a7166aae5908cc819f2d4 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Mar 2015 17:47:08 +0100 Subject: [PATCH 2/5] Fix issues with submodules regarding refcounting. --- src/repository.c | 1 + src/submodule.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/repository.c b/src/repository.c index b142c91..4a8d14f 100644 --- a/src/repository.c +++ b/src/repository.c @@ -80,6 +80,7 @@ wrap_repository(git_repository *c_repo) py_repo->repo = c_repo; py_repo->config = NULL; py_repo->index = NULL; + py_repo->owned = 1; } return (PyObject *)py_repo; diff --git a/src/submodule.c b/src/submodule.c index 1dbed33..93b9775 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -69,7 +69,9 @@ PyDoc_STRVAR(Submodule_path__doc__, PyObject * Submodule_path__get__(Submodule *self) { - return to_unicode(git_submodule_path(self->submodule), NULL, NULL); + const char *path = git_submodule_path(self->submodule); + assert(path); + return to_unicode(path, NULL, NULL); } PyDoc_STRVAR(Submodule_url__doc__, @@ -80,7 +82,7 @@ Submodule_url__get__(Submodule *self) { const char *url = git_submodule_url(self->submodule); if (url == NULL) - return Py_None; + Py_RETURN_NONE; return to_unicode(url, NULL, NULL); } @@ -92,7 +94,7 @@ Submodule_branch__get__(Submodule *self) { const char *branch = git_submodule_branch(self->submodule); if (branch == NULL) - return Py_None; + Py_RETURN_NONE; return to_unicode(branch, NULL, NULL); } @@ -168,8 +170,8 @@ wrap_submodule(Repository *repo, git_submodule *c_submodule) py_submodule = PyObject_New(Submodule, &SubmoduleType); if (py_submodule) { py_submodule->submodule = c_submodule; + py_submodule->repo = repo; if (repo) { - py_submodule->repo = repo; Py_INCREF(repo); } } From d35ecf945a14bfdad3523a0b916697327be06a31 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Mar 2015 17:48:29 +0100 Subject: [PATCH 3/5] Add tests for submodules. --- test/data/submodulerepo.tar | Bin 0 -> 143360 bytes test/test_submodule.py | 73 ++++++++++++++++++++++++++++++++++++ test/utils.py | 4 ++ 3 files changed, 77 insertions(+) create mode 100644 test/data/submodulerepo.tar create mode 100644 test/test_submodule.py diff --git a/test/data/submodulerepo.tar b/test/data/submodulerepo.tar new file mode 100644 index 0000000000000000000000000000000000000000..9292bc64285ece80f5355c544c65c386e3e48600 GIT binary patch literal 143360 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 Date: Mon, 9 Mar 2015 13:27:12 +0100 Subject: [PATCH 4/5] Fully implement Submodule type in C. --- pygit2/submodule.py | 60 --------------------------------------------- src/submodule.c | 11 ++++++++- 2 files changed, 10 insertions(+), 61 deletions(-) delete mode 100644 pygit2/submodule.py diff --git a/pygit2/submodule.py b/pygit2/submodule.py deleted file mode 100644 index 4b1ac10..0000000 --- a/pygit2/submodule.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2010-2015 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. - -# Import from the future -from __future__ import absolute_import - -# Import from pygit2 -from _pygit2 import Submodule as _Submodule - -from .ffi import ffi - - -class Submodule(_Submodule): - - def __init__(self, *args, **kwargs): - super(Submodule, self).__init__(*args, **kwargs) - self._common_init() - - @classmethod - def _from_c(cls, ptr, owned): - cptr = ffi.new('git_submodule **') - cptr[0] = ptr - submodule = cls.__new__(cls) - super(cls, submodule)._from_c(bytes(ffi.buffer(cptr)[:]), owned) - submodule._common_init() - return submodule - - def _common_init(self): - # Get the pointer as the contents of a buffer and store it for - # later access - submodule_cptr = ffi.new('git_submodule **') - ffi.buffer(submodule_cptr)[:] = self._pointer[:] - self._submodule = submodule_cptr[0] - - def __repr__(self): - return "pygit2.Submodule(%r)" % self.name diff --git a/src/submodule.c b/src/submodule.c index 93b9775..b4f05fb 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -98,6 +98,15 @@ Submodule_branch__get__(Submodule *self) return to_unicode(branch, NULL, NULL); } +PyObject * +Submodule_repr(PyObject *self) +{ + Submodule *subm = (Submodule *)self; + + return PyString_FromFormat("pygit2.Submodule(\"%s\")", + git_submodule_name(subm->submodule)); +} + static void Submodule_dealloc(Submodule *self) { @@ -131,7 +140,7 @@ PyTypeObject SubmoduleType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - 0, /* tp_repr */ + Submodule_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ From 9a4e002864fb84956b62788740cc5af8b8b6201a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 9 Mar 2015 13:35:47 +0100 Subject: [PATCH 5/5] Fix build error with Python3 due to PyString_FromFormat. --- src/utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.h b/src/utils.h index 7fd1690..e0f3d00 100644 --- a/src/utils.h +++ b/src/utils.h @@ -61,6 +61,7 @@ #define PyInteger_Type PyLong_Type #define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict") #define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict") + #define PyString_FromFormat(s, ...) PyUnicode_FromFormat(s, __VA_ARGS__) #endif #ifdef PYPY_VERSION