diff --git a/pygit2/__init__.py b/pygit2/__init__.py index 2dbda72..62954f6 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -38,6 +38,7 @@ from .version import __version__ from .settings import Settings from .credentials import * from .remote import Remote, get_credentials +from .config import Config from .errors import check_error from .ffi import ffi, C, to_str diff --git a/pygit2/config.py b/pygit2/config.py new file mode 100644 index 0000000..80f38dc --- /dev/null +++ b/pygit2/config.py @@ -0,0 +1,278 @@ +# -*- 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. + +# Import from the future +from __future__ import absolute_import, unicode_literals + +from _pygit2 import Oid + +from .ffi import ffi, C, to_str, is_string +from .errors import check_error, GitError +from .refspec import Refspec + +def assert_string(v, desc): + if not is_string(v): + raise TypeError("%s must be a string" % desc) + +class ConfigIterator(object): + + def __init__(self, config, ptr): + self._iter = ptr + self._config = config + + def __del__(self): + C.git_config_iterator_free(self._iter) + + def __iter__(self): + return self + + def _next_entry(self): + centry = ffi.new('git_config_entry **') + err = C.git_config_next(centry, self._iter) + check_error(err) + + return centry[0] + + def next(self): + return self.__next__() + + def __next__(self): + entry = self._next_entry() + name = ffi.string(entry.name).decode('utf-8') + value = ffi.string(entry.value).decode('utf-8') + + return name, value + +class ConfigMultivarIterator(ConfigIterator): + def __next__(self): + entry = self._next_entry() + + return ffi.string(entry.value).decode('utf-8') + +class Config(object): + """Git configuration management""" + + def __init__(self, path=None): + cconfig = ffi.new('git_config **') + + if not path: + err = C.git_config_new(cconfig) + else: + assert_string(path, "path") + err = C.git_config_open_ondisk(cconfig, to_str(path)) + + check_error(err, True) + self._config = cconfig[0] + + @classmethod + def from_c(cls, repo, ptr): + config = cls.__new__(cls) + config._repo = repo + config._config = ptr + + return config + + def __del__(self): + C.git_config_free(self._config) + + def _get(self, key): + assert_string(key, "key") + + cstr = ffi.new('char **') + err = C.git_config_get_string(cstr, self._config, to_str(key)) + + return err, cstr + + def _get_string(self, key): + err, cstr = self._get(key) + + if err == C.GIT_ENOTFOUND: + raise KeyError(key) + + check_error(err) + return cstr[0] + + def __contains__(self, key): + err, cstr = self._get(key) + + if err == C.GIT_ENOTFOUND: + return False + + check_error(err) + + return True + + def __getitem__(self, key): + val = self._get_string(key) + + return ffi.string(val).decode() + + def __setitem__(self, key, value): + assert_string(key, "key") + + err = 0 + if isinstance(value, bool): + err = C.git_config_set_bool(self._config, to_str(key), value) + elif isinstance(value, int): + err = C.git_config_set_int64(self._config, to_str(key), value) + else: + err = C.git_config_set_string(self._config, to_str(key), to_str(value)) + + check_error(err) + + def __delitem__(self, key): + assert_string(key, "key") + + err = C.git_config_delete_entry(self._config, to_str(key)) + check_error(err) + + def __iter__(self): + citer = ffi.new('git_config_iterator **') + err = C.git_config_iterator_new(citer, self._config) + check_error(err) + + return ConfigIterator(self, citer[0]) + + def get_multivar(self, name, regex=None): + """get_multivar(name[, regex]) -> [str, ...] + + Get each value of a multivar ''name'' as a list. The optional ''regex'' + parameter is expected to be a regular expression to filter the variables + we're interested in.""" + + assert_string(name, "name") + + citer = ffi.new('git_config_iterator **') + err = C.git_config_multivar_iterator_new(citer, self._config, to_str(name), to_str(regex)) + check_error(err) + + return ConfigMultivarIterator(self, citer[0]) + + def set_multivar(self, name, regex, value): + """set_multivar(name, regex, value) + + Set a multivar ''name'' to ''value''. ''regexp'' is a regular expression + to indicate which values to replace""" + + assert_string(name, "name") + assert_string(regex, "regex") + assert_string(value, "value") + + err = C.git_config_set_multivar(self._config, to_str(name), to_str(regex), to_str(value)) + check_error(err) + + def get_bool(self, key): + """get_bool(key) -> Bool + + Look up *key* and parse its value as a boolean as per the git-config rules + + Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false', + 0, 'off' and 'no'""" + + val = self._get_string(key) + res = ffi.new('int *') + err = C.git_config_parse_bool(res, val) + check_error(err) + + return res[0] != 0 + + def get_int(self, key): + """get_int(key) -> int + + Look up *key* and parse its value as an integer as per the git-config rules. + + A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo', 'mega' and + 'giga' respectively""" + + val = self._get_string(key) + res = ffi.new('int64_t *') + err = C.git_config_parse_int64(res, val) + check_error(err) + + return res[0] + + def add_file(self, path, level=0, force=0): + """add_file(path, level=0, force=0) + + Add a config file instance to an existing config.""" + + err = C.git_config_add_file_ondisk(self._config, to_str(path), level, force) + check_error(err) + + # + # Methods to parse a string according to the git-config rules + # + + @staticmethod + def parse_bool(text): + res = ffi.new('int *') + err = C.git_config_parse_bool(res, to_str(text)) + + return res[0] != 0 + + @staticmethod + def parse_int(text): + res = ffi.new('int64_t *') + err = C.git_config_parse_int64(res, to_str(text)) + check_error(err) + + return res[0] + + # + # Static methods to get specialized version of the config + # + + @staticmethod + def _from_found_config(fn): + buf = ffi.new('char []', C.GIT_PATH_MAX) + err = fn(buf, C.GIT_PATH_MAX) + check_error(err, True) + return Config(ffi.string(buf).decode()) + + @staticmethod + def get_system_config(): + """get_system_config() -> Config + + Return an object representing the system configuration file.""" + + return Config._from_found_config(C.git_config_find_system) + + @staticmethod + def get_global_config(): + """get_global_config() -> Config + + Return an object representing the global configuration file.""" + + return Config._from_found_config(C.git_config_find_global) + + @staticmethod + def get_xdg_config(): + """get_xdg_config() -> Config + + Return an object representing the global configuration file.""" + + return Config._from_found_config(C.git_config_find_xdg) diff --git a/pygit2/decl.h b/pygit2/decl.h index a64c32f..29d4e1c 100644 --- a/pygit2/decl.h +++ b/pygit2/decl.h @@ -5,8 +5,11 @@ typedef ... git_push; typedef ... git_cred; typedef ... git_diff_file; typedef ... git_tree; +typedef ... git_config; +typedef ... git_config_iterator; #define GIT_OID_RAWSZ ... +#define GIT_PATH_MAX ... typedef struct git_oid { unsigned char id[20]; @@ -212,3 +215,49 @@ int git_clone(git_repository **out, const char *url, const char *local_path, const git_clone_options *options); + + +typedef enum { + GIT_CONFIG_LEVEL_SYSTEM = 1, + GIT_CONFIG_LEVEL_XDG = 2, + GIT_CONFIG_LEVEL_GLOBAL = 3, + GIT_CONFIG_LEVEL_LOCAL = 4, + GIT_CONFIG_LEVEL_APP = 5, + GIT_CONFIG_HIGHEST_LEVEL = -1, +} git_config_level_t; + +typedef struct { + const char *name; + const char *value; + git_config_level_t level; +} git_config_entry; + +int git_repository_config(git_config **out, git_repository *repo); +void git_config_free(git_config *cfg); + +int git_config_get_string(const char **out, const git_config *cfg, const char *name); +int git_config_set_string(git_config *cfg, const char *name, const char *value); +int git_config_set_bool(git_config *cfg, const char *name, int value); +int git_config_set_int64(git_config *cfg, const char *name, int64_t value); + +int git_config_parse_bool(int *out, const char *value); +int git_config_parse_int64(int64_t *out, const char *value); + +int git_config_delete_entry(git_config *cfg, const char *name); +int git_config_add_file_ondisk(git_config *cfg, + const char *path, + git_config_level_t level, + int force); + +int git_config_iterator_new(git_config_iterator **out, const git_config *cfg); +int git_config_next(git_config_entry **entry, git_config_iterator *iter); +void git_config_iterator_free(git_config_iterator *iter); + +int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp); +int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value); + +int git_config_new(git_config **out); +int git_config_open_ondisk(git_config **out, const char *path); +int git_config_find_system(char *out, size_t length); +int git_config_find_global(char *out, size_t length); +int git_config_find_xdg(char *out, size_t length); diff --git a/pygit2/errors.py b/pygit2/errors.py index b9f6c9b..398d08c 100644 --- a/pygit2/errors.py +++ b/pygit2/errors.py @@ -33,7 +33,7 @@ from .ffi import ffi, C from _pygit2 import GitError -def check_error(err): +def check_error(err, io=False): if err >= 0: return @@ -45,7 +45,10 @@ def check_error(err): if err in [C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EEXISTS, C.GIT_EAMBIGUOUS]: raise ValueError(message) elif err == C.GIT_ENOTFOUND: - raise KeyError(message) + if io: + raise IOError(message) + else: + raise KeyError(message) elif err == C.GIT_EINVALIDSPEC: raise ValueError(message) elif err == C.GIT_ITEROVER: diff --git a/pygit2/repository.py b/pygit2/repository.py index a0f8507..3f18c2c 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -38,6 +38,7 @@ from _pygit2 import Reference, Tree, Commit, Blob from .ffi import ffi, C, to_str from .errors import check_error from .remote import Remote +from .config import Config class Repository(_Repository): @@ -110,6 +111,23 @@ class Repository(_Repository): C.git_strarray_free(names) + # + # Configuration + # + @property + def config(self): + """The configuration file for this repository + + If a the configuration hasn't been set yet, the default config for + repository will be returned, including global and system configurations + (if they are available).""" + + cconfig = ffi.new('git_config **') + err = C.git_repository_config(cconfig, self._repo) + check_error(err) + + return Config.from_c(self, cconfig[0]) + # # References # diff --git a/src/config.c b/src/config.c deleted file mode 100644 index 07dbb40..0000000 --- a/src/config.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * 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 "error.h" -#include "types.h" -#include "utils.h" -#include "config.h" - -extern PyTypeObject ConfigType; -extern PyTypeObject ConfigIterType; - - -PyObject * -wrap_config(char *c_path) { - int err; - PyObject *py_path; - Config *py_config; - - py_path = Py_BuildValue("(s)", c_path); - py_config = PyObject_New(Config, &ConfigType); - - err = Config_init(py_config, py_path, NULL); - if (err < 0) - return NULL; - - return (PyObject*) py_config; -} - - -int -Config_init(Config *self, PyObject *args, PyObject *kwds) -{ - char *path = NULL; - int err; - - if (kwds && PyDict_Size(kwds) > 0) { - PyErr_SetString(PyExc_TypeError, - "Config takes no keyword arguments"); - return -1; - } - - if (!PyArg_ParseTuple(args, "|s", &path)) - return -1; - - if (path == NULL) - err = git_config_new(&self->config); - else - err = git_config_open_ondisk(&self->config, path); - - if (err < 0) { - git_config_free(self->config); - - if (err == GIT_ENOTFOUND) - Error_set_exc(PyExc_IOError); - else - Error_set(err); - - return -1; - } - - return 0; -} - - -void -Config_dealloc(Config *self) -{ - git_config_free(self->config); - Py_TYPE(self)->tp_free(self); -} - -PyDoc_STRVAR(Config_get_global_config__doc__, - "get_global_config() -> Config\n" - "\n" - "Return an object representing the global configuration file."); - -PyObject * -Config_get_global_config(void) -{ - char path[GIT_PATH_MAX]; - int err; - - err = git_config_find_global(path, GIT_PATH_MAX); - if (err < 0) { - if (err == GIT_ENOTFOUND) { - PyErr_SetString(PyExc_IOError, "Global config file not found."); - return NULL; - } - - return Error_set(err); - } - - return wrap_config(path); -} - - -PyDoc_STRVAR(Config_get_system_config__doc__, - "get_system_config() -> Config\n" - "\n" - "Return an object representing the system configuration file."); - -PyObject * -Config_get_system_config(void) -{ - char path[GIT_PATH_MAX]; - int err; - - err = git_config_find_system(path, GIT_PATH_MAX); - if (err < 0) { - if (err == GIT_ENOTFOUND) { - PyErr_SetString(PyExc_IOError, "System config file not found."); - return NULL; - } - return Error_set(err); - } - - return wrap_config(path); -} - - -int -Config_contains(Config *self, PyObject *py_key) { - int err; - const char *c_value, *c_key; - PyObject *tkey; - - c_key = py_str_borrow_c_str(&tkey, py_key, NULL); - if (c_key == NULL) - return -1; - - err = git_config_get_string(&c_value, self->config, c_key); - Py_DECREF(tkey); - - if (err < 0) { - if (err == GIT_ENOTFOUND) - return 0; - - Error_set(err); - return -1; - } - - return 1; -} - -/* Get the C string value given a python string as key */ -static int -get_string(const char **key_out, Config *self, PyObject *py_key) -{ - PyObject *tkey; - const char *key; - int err; - - key = py_str_borrow_c_str(&tkey, py_key, NULL); - if (key == NULL) - return -1; - - err = git_config_get_string(key_out, self->config, key); - Py_CLEAR(tkey); - - if (err == GIT_ENOTFOUND) { - PyErr_SetObject(PyExc_KeyError, py_key); - return -1; - } - - if (err < 0) { - Error_set(err); - return -1; - } - - return 0; -} - -PyObject * -Config_getitem(Config *self, PyObject *py_key) -{ - int err; - const char *value_str; - - err = get_string(&value_str, self, py_key); - if (err < 0) - return NULL; - - return to_unicode(value_str, NULL, NULL); -} - -PyDoc_STRVAR(Config_get_bool__doc__, - "get_bool(key) -> Bool\n" - "\n" - "Look up *key* and parse its value as a boolean as per the git-config rules\n" - "\n" - "Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false',\n" - "0, 'off' and 'no'"); - -PyObject * -Config_get_bool(Config *self, PyObject *key) -{ - int err, value; - const char *value_str; - - err = get_string(&value_str, self, key); - if (err < 0) - return NULL; - - if ((err = git_config_parse_bool(&value, value_str)) < 0) - return NULL; - - return PyBool_FromLong(value); -} - -PyDoc_STRVAR(Config_get_int__doc__, - "get_int(key) -> int\n" - "\n" - "Look up *key* and parse its value as an integer as per the git-config rules\n" - "\n" - "A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo', 'mega' and\n" - "'giga' respectively"); - -PyObject * -Config_get_int(Config *self, PyObject *key) -{ - int err; - int64_t value; - const char *value_str; - - err = get_string(&value_str, self, key); - if (err < 0) - return NULL; - - if ((err = git_config_parse_int64(&value, value_str)) < 0) - return NULL; - - return PyLong_FromLongLong(value); -} - -int -Config_setitem(Config *self, PyObject *py_key, PyObject *py_value) -{ - int err; - const char *key, *value; - PyObject *tkey, *tvalue; - - key = py_str_borrow_c_str(&tkey, py_key, NULL); - if (key == NULL) - return -1; - - if (py_value == NULL) - err = git_config_delete_entry(self->config, key); - else if (PyBool_Check(py_value)) { - err = git_config_set_bool(self->config, key, - (int)PyObject_IsTrue(py_value)); - } else if (PyLong_Check(py_value)) { - err = git_config_set_int64(self->config, key, - (int64_t)PyLong_AsLong(py_value)); - } else { - value = py_str_borrow_c_str(&tvalue, py_value, NULL); - err = git_config_set_string(self->config, key, value); - Py_DECREF(tvalue); - } - - Py_DECREF(tkey); - if (err < 0) { - Error_set(err); - return -1; - } - return 0; -} - -PyDoc_STRVAR(Config_add_file__doc__, - "add_file(path, level=0, force=0)\n" - "\n" - "Add a config file instance to an existing config."); - -PyObject * -Config_add_file(Config *self, PyObject *args, PyObject *kwds) -{ - char *keywords[] = {"path", "level", "force", NULL}; - int err; - char *path; - unsigned int level = 0; - int force = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|Ii", keywords, - &path, &level, &force)) - return NULL; - - err = git_config_add_file_ondisk(self->config, path, level, force); - if (err < 0) - return Error_set_str(err, path); - - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(Config_get_multivar__doc__, - "get_multivar(name[, regex]) -> [str, ...]\n" - "\n" - "Get each value of a multivar ''name'' as a list. The optional ''regex''\n" - "parameter is expected to be a regular expression to filter the variables\n" - "we're interested in."); - -PyObject * -Config_get_multivar(Config *self, PyObject *args) -{ - int err; - PyObject *list; - const char *name = NULL; - const char *regex = NULL; - git_config_iterator *iter; - git_config_entry *entry; - - if (!PyArg_ParseTuple(args, "s|s", &name, ®ex)) - return NULL; - - list = PyList_New(0); - err = git_config_multivar_iterator_new(&iter, self->config, name, regex); - if (err < 0) - return Error_set(err); - - while ((err = git_config_next(&entry, iter)) == 0) { - PyObject *item; - - item = to_unicode(entry->value, NULL, NULL); - if (item == NULL) { - git_config_iterator_free(iter); - return NULL; - } - - PyList_Append(list, item); - Py_CLEAR(item); - } - - git_config_iterator_free(iter); - if (err == GIT_ITEROVER) - err = 0; - - if (err < 0) - return Error_set(err); - - return list; -} - - -PyDoc_STRVAR(Config_set_multivar__doc__, - "set_multivar(name, regex, value)\n" - "\n" - "Set a multivar ''name'' to ''value''. ''regexp'' is a regular expression\n" - "to indicate which values to replace"); - -PyObject * -Config_set_multivar(Config *self, PyObject *args) -{ - int err; - const char *name = NULL; - const char *regex = NULL; - const char *value = NULL; - - if (!PyArg_ParseTuple(args, "sss", &name, ®ex, &value)) - return NULL; - - err = git_config_set_multivar(self->config, name, regex, value); - if (err < 0) { - if (err == GIT_ENOTFOUND) - Error_set(err); - else - PyErr_SetNone(PyExc_TypeError); - return NULL; - } - - Py_RETURN_NONE; -} - -PyObject * -Config_iter(Config *self) -{ - ConfigIter *iter; - int err; - - iter = PyObject_New(ConfigIter, &ConfigIterType); - if (!iter) - return NULL; - - if ((err = git_config_iterator_new(&iter->iter, self->config)) < 0) - return Error_set(err); - - Py_INCREF(self); - iter->owner = self; - - return (PyObject*)iter; -} - -PyMethodDef Config_methods[] = { - METHOD(Config, get_system_config, METH_NOARGS | METH_STATIC), - METHOD(Config, get_global_config, METH_NOARGS | METH_STATIC), - METHOD(Config, add_file, METH_VARARGS | METH_KEYWORDS), - METHOD(Config, get_multivar, METH_VARARGS), - METHOD(Config, set_multivar, METH_VARARGS), - METHOD(Config, get_bool, METH_O), - METHOD(Config, get_int, METH_O), - {NULL} -}; - -PySequenceMethods Config_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)Config_contains, /* sq_contains */ -}; - -PyMappingMethods Config_as_mapping = { - 0, /* mp_length */ - (binaryfunc)Config_getitem, /* mp_subscript */ - (objobjargproc)Config_setitem, /* mp_ass_subscript */ -}; - - -PyDoc_STRVAR(Config__doc__, "Configuration management."); - -PyTypeObject ConfigType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pygit2.Config", /* tp_name */ - sizeof(Config), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Config_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &Config_as_sequence, /* tp_as_sequence */ - &Config_as_mapping, /* 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 */ - Config__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)Config_iter, /* tp_iter */ - 0, /* tp_iternext */ - Config_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Config_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -void -ConfigIter_dealloc(ConfigIter *self) -{ - Py_CLEAR(self->owner); - git_config_iterator_free(self->iter); - PyObject_Del(self); -} - -PyObject * -ConfigIter_iternext(ConfigIter *self) -{ - int err; - git_config_entry *entry; - - if ((err = git_config_next(&entry, self->iter)) < 0) - return Error_set(err); - - return Py_BuildValue("ss", entry->name, entry->value); -} - -PyDoc_STRVAR(ConfigIter__doc__, "Configuration iterator."); - -PyTypeObject ConfigIterType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pygit2.ConfigIter", /* tp_name */ - sizeof(ConfigIter), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)ConfigIter_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - ConfigIter__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)ConfigIter_iternext, /* tp_iternext */ - -}; diff --git a/src/config.h b/src/config.h deleted file mode 100644 index ffa0733..0000000 --- a/src/config.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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_config_h -#define INCLUDE_pygit2_config_h - -#define PY_SSIZE_T_CLEAN -#include -#include - -PyObject* wrap_config(char *c_path); -PyObject* Config_get_global_config(void); -PyObject* Config_get_system_config(void); -PyObject* Config_add_file(Config *self, PyObject *args, PyObject *kwds); -PyObject* Config_getitem(Config *self, PyObject *key); -PyObject* Config_foreach(Config *self, PyObject *args); -PyObject* Config_get_multivar(Config *self, PyObject *args); -PyObject* Config_set_multivar(Config *self, PyObject *args); -int Config_init(Config *self, PyObject *args, PyObject *kwds); -int Config_setitem(Config *self, PyObject *key, PyObject *value); -#endif diff --git a/src/pygit2.c b/src/pygit2.c index d88c0e4..2ed0808 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -66,8 +66,6 @@ extern PyTypeObject IndexType; extern PyTypeObject IndexEntryType; extern PyTypeObject IndexIterType; extern PyTypeObject WalkerType; -extern PyTypeObject ConfigType; -extern PyTypeObject ConfigIterType; extern PyTypeObject ReferenceType; extern PyTypeObject RefLogIterType; extern PyTypeObject RefLogEntryType; @@ -385,11 +383,6 @@ moduleinit(PyObject* m) 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) - ADD_TYPE(m, ConfigIter) - /* Blame */ INIT_TYPE(BlameType, NULL, NULL) INIT_TYPE(BlameIterType, NULL, NULL) diff --git a/src/repository.c b/src/repository.c index 051ccb3..9f78480 100644 --- a/src/repository.c +++ b/src/repository.c @@ -513,45 +513,6 @@ Repository_workdir__get__(Repository *self, void *closure) return to_path(c_path); } - -PyDoc_STRVAR(Repository_config__doc__, - "Get the configuration file for this repository.\n" - "\n" - "If a configuration file has not been set, the default config set for the\n" - "repository will be returned, including global and system configurations\n" - "(if they are available)."); - -PyObject * -Repository_config__get__(Repository *self) -{ - int err; - git_config *config; - Config *py_config; - - assert(self->repo); - - if (self->config == NULL) { - err = git_repository_config(&config, self->repo); - if (err < 0) - return Error_set(err); - - py_config = PyObject_New(Config, &ConfigType); - if (py_config == NULL) { - git_config_free(config); - return NULL; - } - - py_config->config = config; - self->config = (PyObject*)py_config; - /* We need 2 refs here. One is returned, one is kept internally. */ - Py_INCREF(self->config); - } else { - Py_INCREF(self->config); - } - - return self->config; -} - PyDoc_STRVAR(Repository_merge_base__doc__, "merge_base(oid, oid) -> Oid\n" "\n" @@ -1601,7 +1562,6 @@ PyGetSetDef Repository_getseters[] = { GETTER(Repository, head_is_unborn), GETTER(Repository, is_empty), GETTER(Repository, is_bare), - GETTER(Repository, config), GETTER(Repository, workdir), GETTER(Repository, default_signature), GETTER(Repository, _pointer), diff --git a/src/types.h b/src/types.h index e50f834..c39ade9 100644 --- a/src/types.h +++ b/src/types.h @@ -70,19 +70,6 @@ SIMPLE_TYPE(Tree, git_tree, tree) SIMPLE_TYPE(Blob, git_blob, blob) SIMPLE_TYPE(Tag, git_tag, tag) - -/* git_config */ -typedef struct { - PyObject_HEAD - git_config* config; -} Config; - -typedef struct { - PyObject_HEAD - Config *owner; - git_config_iterator *iter; -} ConfigIter; - /* git_note */ typedef struct { PyObject_HEAD diff --git a/test/test_config.py b/test/test_config.py index 937ed1b..9787c3e 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -115,9 +115,10 @@ class ConfigTest(utils.RepoTestCase): config.add_file(CONFIG_FILENAME, 0) self.assertTrue('this.that' in config) - self.assertEqual(len(config.get_multivar('this.that')), 2) - l = config.get_multivar('this.that', 'bar') - self.assertEqual(len(l), 1) + + self.assertEqual(2, len(list(config.get_multivar('this.that')))) + l = list(config.get_multivar('this.that', 'bar')) + self.assertEqual(1, len(l)) self.assertEqual(l[0], 'foobar') def test_write(self): @@ -155,16 +156,16 @@ class ConfigTest(utils.RepoTestCase): config.add_file(CONFIG_FILENAME, 5) self.assertTrue('this.that' in config) l = config.get_multivar('this.that', 'foo.*') - self.assertEqual(len(l), 2) + self.assertEqual(2, len(list(l))) config.set_multivar('this.that', '^.*beer', 'fool') - l = config.get_multivar('this.that', 'fool') + l = list(config.get_multivar('this.that', 'fool')) self.assertEqual(len(l), 1) self.assertEqual(l[0], 'fool') config.set_multivar('this.that', 'foo.*', 'foo-123456') l = config.get_multivar('this.that', 'foo.*') - self.assertEqual(len(l), 2) + self.assertEqual(2, len(list(l))) for i in l: self.assertEqual(i, 'foo-123456') @@ -178,5 +179,12 @@ class ConfigTest(utils.RepoTestCase): self.assertTrue('core.bare' in lst) self.assertTrue(lst['core.bare']) + def test_parsing(self): + self.assertTrue(Config.parse_bool("on")) + self.assertTrue(Config.parse_bool("1")) + + self.assertEqual(5, Config.parse_int("5")) + self.assertEqual(1024, Config.parse_int("1k")) + if __name__ == '__main__': unittest.main()