From ab441967302b0d2eafb84a1c0a7bad90edc99156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 23 Mar 2014 12:55:12 +0100 Subject: [PATCH] Introduce libgit2 options Allow setting and getting the mwindow size and search paths. --- src/options.c | 185 +++++++++++++++++++++++++++++++++++++++++++ src/options.h | 51 ++++++++++++ src/pygit2.c | 13 +++ test/test_options.py | 57 +++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 src/options.c create mode 100644 src/options.h create mode 100644 test/test_options.py diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..abfa465 --- /dev/null +++ b/src/options.c @@ -0,0 +1,185 @@ +/* + * Copyright 2010-2014 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 "types.h" +#include "utils.h" + +extern PyObject *GitError; + +static PyObject * +get_search_path(long level) +{ + char *buf = NULL; + size_t len = 64; + PyObject *py_path; + int error; + + do { + len *= 2; + char *tmp = realloc(buf, len); + if (!tmp) { + free(buf); + PyErr_NoMemory(); + return NULL; + } + buf = tmp; + + error = git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, level, buf, len); + } while(error == GIT_EBUFS); + + if (error < 0) { + free(buf); + Error_set(error); + return NULL; + } + + if (!buf) + return NULL; + + py_path = to_unicode(buf, NULL, NULL); + free(buf); + + if (!py_path) + return NULL; + + return py_path; +} + +PyObject * +option(PyObject *self, PyObject *args) +{ + long option; + int error; + PyObject *py_option; + + py_option = PyTuple_GetItem(args, 0); + if (!py_option) + return NULL; + + if (!PyLong_Check(py_option)) + goto on_non_integer; + + option = PyLong_AsLong(py_option); + + switch (option) { + case GIT_OPT_GET_SEARCH_PATH: + { + PyObject *py_level; + + py_level = PyTuple_GetItem(args, 1); + if (!py_level) + return NULL; + + if (!PyLong_Check(py_level)) + goto on_non_integer; + + return get_search_path(PyLong_AsLong(py_level)); + break; + } + + case GIT_OPT_SET_SEARCH_PATH: + { + PyObject *py_level, *py_path, *tpath; + const char *path; + int err; + + py_level = PyTuple_GetItem(args, 1); + if (!py_level) + return NULL; + + py_path = PyTuple_GetItem(args, 2); + if (!py_path) + return NULL; + + if (!PyLong_Check(py_level)) + goto on_non_integer; + + path = py_str_borrow_c_str(&tpath, py_path, NULL); + if (!path) + return NULL; + + err = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, PyLong_AsLong(py_level), path); + Py_DECREF(tpath); + + if (err < 0) { + Error_set(err); + return NULL; + } + + Py_RETURN_NONE; + break; + } + + case GIT_OPT_GET_MWINDOW_SIZE: + { + size_t size; + + if ((error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &size)) < 0) { + Error_set(error); + return NULL; + } + + return PyLong_FromSize_t(size); + + break; + } + + case GIT_OPT_SET_MWINDOW_SIZE: + { + size_t size; + PyObject *py_size; + + py_size = PyTuple_GetItem(args, 1); + if (!py_size) + return NULL; + + if (!PyLong_Check(py_size)) + goto on_non_integer; + + + size = PyLong_AsSize_t(py_size); + if ((error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, size)) < 0) { + Error_set(error); + return NULL; + } + + Py_RETURN_NONE; + break; + } + } + + PyErr_SetString(PyExc_ValueError, "unknown/unsupported option value"); + return NULL; + +on_non_integer: + PyErr_SetString(PyExc_TypeError, "option is not an integer"); + return NULL; +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..8dccda1 --- /dev/null +++ b/src/options.h @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2014 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_blame_h +#define INCLUDE_pygit2_blame_h + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "types.h" + +PyDoc_STRVAR(option__doc__, + "Get or set a libgit2 option\n" + "Arguments:\n" + " (GIT_OPT_GET_SEARCH_PATH, level)\n" + " Get the config search path for the given level\n" + " (GIT_OPT_SET_SEARCH_PATH, level, path)\n" + " Set the config search path for the given level\n" + " (GIT_OPT_GET_MWINDOW_SIZE)\n" + " Get the maximum mmap window size\n" + " (GIT_OPT_SET_MWINDOW_SIZE, size)\n" + " Set the maximum mmap window size\n"); + + +PyObject *option(PyObject *self, PyObject *args); + +#endif diff --git a/src/pygit2.c b/src/pygit2.c index 77535c7..9b6319e 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -39,6 +39,7 @@ #include "utils.h" #include "repository.h" #include "oid.h" +#include "options.h" /* FIXME: This is for pypy */ #ifndef MAXPATHLEN @@ -244,6 +245,7 @@ PyMethodDef module_methods[] = { discover_repository__doc__}, {"hashfile", hashfile, METH_VARARGS, hashfile__doc__}, {"hash", hash, METH_VARARGS, hash__doc__}, + {"option", option, METH_VARARGS, option__doc__}, {NULL} }; @@ -259,6 +261,12 @@ moduleinit(PyObject* m) ADD_CONSTANT_INT(m, LIBGIT2_VER_REVISION) ADD_CONSTANT_STR(m, LIBGIT2_VERSION) + /* libgit2 options */ + ADD_CONSTANT_INT(m, GIT_OPT_GET_SEARCH_PATH); + ADD_CONSTANT_INT(m, GIT_OPT_SET_SEARCH_PATH); + ADD_CONSTANT_INT(m, GIT_OPT_GET_MWINDOW_SIZE); + ADD_CONSTANT_INT(m, GIT_OPT_SET_MWINDOW_SIZE); + /* Errors */ GitError = PyErr_NewException("_pygit2.GitError", NULL, NULL); Py_INCREF(GitError); @@ -424,6 +432,11 @@ moduleinit(PyObject* m) ADD_CONSTANT_INT(m, GIT_DIFF_FIND_AND_BREAK_REWRITES) /* Config */ + ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_LOCAL); + ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_GLOBAL); + ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_XDG); + ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_SYSTEM); + INIT_TYPE(ConfigType, NULL, PyType_GenericNew) INIT_TYPE(ConfigIterType, NULL, NULL) ADD_TYPE(m, Config) diff --git a/test/test_options.py b/test/test_options.py new file mode 100644 index 0000000..e35f520 --- /dev/null +++ b/test/test_options.py @@ -0,0 +1,57 @@ +# -*- coding: UTF-8 -*- +# +# Copyright 2010-2014 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 Blame objects.""" + +from __future__ import absolute_import +from __future__ import unicode_literals +import unittest +import pygit2 +from pygit2 import GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE +from pygit2 import GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH +from pygit2 import GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_XDG, GIT_CONFIG_LEVEL_GLOBAL +from pygit2 import option +from . import utils + +class OptionsTest(utils.NoRepoTestCase): + + def test_mwindow_size(self): + new_size = 200 * 1024 + option(GIT_OPT_SET_MWINDOW_SIZE, new_size) + self.assertEqual(new_size, option(GIT_OPT_GET_MWINDOW_SIZE)) + + def test_search_path(self): + paths = [(GIT_CONFIG_LEVEL_GLOBAL, '/tmp/global'), + (GIT_CONFIG_LEVEL_XDG, '/tmp/xdg'), + (GIT_CONFIG_LEVEL_SYSTEM, '/tmp/etc')] + + for level, path in paths: + option(GIT_OPT_SET_SEARCH_PATH, level, path) + self.assertEqual(path, option(GIT_OPT_GET_SEARCH_PATH, level)) + +if __name__ == '__main__': + unittest.main()