From e126b09380c44d87967a284bca3427450990bd2d Mon Sep 17 00:00:00 2001 From: Martin Lenders <mlenders@elegosoft.com> Date: Fri, 8 Jun 2012 17:11:10 +0200 Subject: [PATCH] Implement dictionary-like behaviour for Config --- include/pygit2/config.h | 2 + src/pygit2/config.c | 105 +++++++++++++++++++++++++++++++++- test/data/testrepo.git/config | 1 + test/data/testrepo.tar | Bin 61440 -> 61440 bytes test/test_config.py | 62 ++++++++++++++++++++ 5 files changed, 168 insertions(+), 2 deletions(-) diff --git a/include/pygit2/config.h b/include/pygit2/config.h index d281902..9d6017f 100644 --- a/include/pygit2/config.h +++ b/include/pygit2/config.h @@ -8,5 +8,7 @@ PyObject* Config_get_global_config(void); PyObject* Config_get_system_config(void); PyObject* Config_add_file(Config *self, PyObject *args); +PyObject* Config_getitem(Config *self, PyObject *key); +int Config_setitem(Config *self, PyObject *key, PyObject *value); #endif diff --git a/src/pygit2/config.c b/src/pygit2/config.c index d05f1a7..b18977a 100644 --- a/src/pygit2/config.c +++ b/src/pygit2/config.c @@ -102,6 +102,90 @@ Config_get_system_config(void) return Config_open(path); } +int +Config_contains(Config *self, PyObject *py_key) { + int err; + const char *c_value; + const char *c_key; + + if (!(c_key = py_str_to_c_str(py_key,NULL))) + return -1; + + err = git_config_get_string(&c_value, self->config, c_key); + + if (err == GIT_ENOTFOUND) + return 0; + if (err < 0) { + Error_set(err); + return -1; + } + + return 1; +} + +PyObject * +Config_getitem(Config *self, PyObject *py_key) +{ + int err; + int64_t c_intvalue; + int c_boolvalue; + const char *c_charvalue; + const char *c_key; + + if (!(c_key = py_str_to_c_str(py_key,NULL))) + return NULL; + + err = git_config_get_int64(&c_intvalue, self->config, c_key); + if (err == GIT_OK) { + return PyInt_FromLong((long)c_intvalue); + } + + err = git_config_get_bool(&c_boolvalue, self->config, c_key); + if (err == GIT_OK) { + return PyBool_FromLong((long)c_boolvalue); + } + + err = git_config_get_string(&c_charvalue, self->config, c_key); + if (err < 0) { + if (err == GIT_ENOTFOUND) { + PyErr_SetObject(PyExc_KeyError, py_key); + return NULL; + } + return Error_set(err); + } + + return PyUnicode_FromString(c_charvalue); +} + +int +Config_setitem(Config *self, PyObject *py_key, PyObject *py_value) +{ + int err; + const char *c_key; + + if (!(c_key = py_str_to_c_str(py_key,NULL))) + return -1; + + if (!py_value) { + err = git_config_delete(self->config, c_key); + } else if (PyBool_Check(py_value)) { + err = git_config_set_bool(self->config, c_key, + (int)PyObject_IsTrue(py_value)); + } else if (PyInt_Check(py_value)) { + err = git_config_set_int64(self->config, c_key, + (int64_t)PyInt_AsLong(py_value)); + } else { + py_value = PyObject_Str(py_value); + err = git_config_set_string(self->config, c_key, + py_str_to_c_str(py_value,NULL)); + } + if (err < 0) { + Error_set(err); + return -1; + } + return 0; +} + PyObject * Config_add_file(Config *self, PyObject *args) { @@ -133,6 +217,23 @@ PyMethodDef Config_methods[] = { {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 */ +}; + PyTypeObject ConfigType = { PyVarObject_HEAD_INIT(NULL, 0) "_pygit2.Config", /* tp_name */ @@ -145,8 +246,8 @@ PyTypeObject ConfigType = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + &Config_as_sequence, /* tp_as_sequence */ + &Config_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ diff --git a/test/data/testrepo.git/config b/test/data/testrepo.git/config index 83142d2..6a442c4 100644 --- a/test/data/testrepo.git/config +++ b/test/data/testrepo.git/config @@ -2,5 +2,6 @@ repositoryformatversion = 0 filemode = true bare = true + editor = 'ed' [gc] auto = no diff --git a/test/data/testrepo.tar b/test/data/testrepo.tar index 1b613a8d20cadb866c663c2fb87361d0f0fff861..a064aa21bd9b68483d83340d58b587ada87eccd9 100644 GIT binary patch delta 219 zcmZp8z})bFc>`a<X1<h9$&(T?8O<hViAYPBnlKm|nwy!J7#bUz8#5Rfniv}!Gbk8L zHe^oWEiEodEK*Ql$W1IN$(*bhAk7M6IZt+A?w^ztBcK2TsVSKy`9%u0KnB-l#Yy)W PHycd4Kp(<^V<{s5F>q2} delta 170 zcmZp8z})bFc>`a<WWFQOlQTtRB#ccM3=K_<%#2LUP0bA%3=B<-Obr<n3?>^gr%YyK d{6Fbf%w|K5C5(#_QZ_3bdca5zVzLAC0syUjN0k5o diff --git a/test/test_config.py b/test/test_config.py index 92b7b60..b9e6aae 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -60,6 +60,17 @@ class ConfigTest(utils.RepoTestCase): self.assertNotEqual(config_write, None) + config_write['core.bare'] = False + config_write['core.editor'] = 'ed' + + config_read = pygit2.Config(config_filename) + self.assertTrue('core.bare' in config_write) + self.assertFalse(config_write['core.bare']) + self.assertTrue('core.editor' in config_write) + self.assertEqual(config_write['core.editor'], 'ed') + + os.remove(config_filename) + def test_add(self): config = pygit2.Config.get_global_config() @@ -69,9 +80,60 @@ class ConfigTest(utils.RepoTestCase): new_file.close() config.add_file(config_filename, 0) + self.assertTrue('this.that' in config) + self.assertTrue(config['this.that']) + self.assertTrue('something.other.here' in config) + self.assertFalse(config['something.other.here']) os.remove(config_filename) + def test_read(self): + config = self.repo.config + + self.assertRaises(TypeError, lambda: config[()]) + self.assertRaises(TypeError, lambda: config[-4]) + self.assertRaisesWithArg(pygit2.GitError, + "Invalid variable name: 'abc'", lambda: config['abc']) + self.assertRaisesWithArg(KeyError, 'abc.def', lambda: config['abc.def']) + + self.assertTrue('core.bare' in config) + self.assertFalse(config['core.bare']) + self.assertTrue('core.editor' in config) + self.assertEqual(config['core.editor'], 'ed') + self.assertTrue('core.repositoryformatversion' in config) + self.assertEqual(config['core.repositoryformatversion'], 0) + + new_file = open(config_filename, "w") + new_file.write("[this]\n\tthat = foobar\n\tthat = foobeer\n") + new_file.close() + + def test_write(self): + config = self.repo.config + + with self.assertRaises(TypeError): + config[()] = 'This should not work' + + self.assertFalse('core.dummy1' in config) + config['core.dummy1'] = 42 + self.assertTrue('core.dummy1' in config) + self.assertEqual(config['core.dummy1'], 42) + + self.assertFalse('core.dummy2' in config) + config['core.dummy2'] = 'foobar' + self.assertTrue('core.dummy2' in config) + self.assertEqual(config['core.dummy2'], 'foobar') + + self.assertFalse('core.dummy3' in config) + config['core.dummy3'] = True + self.assertTrue('core.dummy3' in config) + self.assertTrue(config['core.dummy3']) + + del config['core.dummy1'] + self.assertFalse('core.dummy1' in config) + del config['core.dummy2'] + self.assertFalse('core.dummy2' in config) + del config['core.dummy3'] + self.assertFalse('core.dummy3' in config) if __name__ == '__main__':