
This halves the amount of code we have to take into account for dealing with the config. There is a slight change in the API. Config.get_multivar() returns an iterator instead of a list, which lets us reuse code from the general iterator and is closer to libgit2's API.
260 lines
7.4 KiB
Python
260 lines
7.4 KiB
Python
# -*- 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)
|
|
|
|
#
|
|
# 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)
|