diff --git a/AUTHORS b/AUTHORS index 490baad..a8b505e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Creator: Sebastian Thiel +Contributor: Michael Trier (code taken in a modified form from GitPython) diff --git a/doc/source/changes.rst b/doc/source/changes.rst index 7b8ebec..ea8ee80 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -2,6 +2,39 @@ Changelog ######### +**** +NEXT +**** +* == **General Design** == + + * Database Interfaces have no implementation anymore (or only a minimal most general one where adequate). All previous implementation moved to the *py* subdirectory, which is designated to the pure python implementation. It + +* == **Renamed Types** == + + * Renamed type *GitDB* to **GitODB**. *GitDB* now is a new type with more functionality + * Renamed type **FileDB** to **RootPathDB** + * The previous implementations for all types found in db/base.py are now renamed to **Pure** and moved to the db/py/base.py module. + +* == **Renamed Modules** == + + * in *gitdb/db* + + * moved all modules *except for* base.py into **py/** subdirectory + * renamed **base.py** into **interface.py** + +* == **New Modules** == + + * gitdb/db/py/base.py - pure python base implenentations for many simple interfaces which are subsequently used by complex pure implementations. + + +* == **New Interfaces** == + + * Added interface to allow transporting git data: **TransportDB** + * Added interface to handle git related paths: **RepositoryPathsMixin** + * Added interface to read and write git-like configuration: **ConfigurationMixin** + * Added **ReferencesMixin** providing reference resolution. + * Added implementation of git datbase with support for transportation and reference resolution: **GitDB** + ***** 0.5.2 ***** diff --git a/gitdb/config.py b/gitdb/config.py new file mode 100644 index 0000000..a8efe46 --- /dev/null +++ b/gitdb/config.py @@ -0,0 +1,421 @@ +# config.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# Heavily modified by Sebastian Thiel (byronimo@gmail.com) +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php +"""Module containing module parser implementation able to properly read and write +configuration files""" + +import re +import os +import ConfigParser as cp +import inspect +import cStringIO + +from gitdb.odict import OrderedDict +from gitdb.util import LockFile + +__all__ = ('GitConfigParser', 'SectionConstraint') + +class MetaParserBuilder(type): + """Utlity class wrapping base-class methods into decorators that assure read-only properties""" + def __new__(metacls, name, bases, clsdict): + """ + Equip all base-class methods with a needs_values decorator, and all non-const methods + with a set_dirty_and_flush_changes decorator in addition to that.""" + kmm = '_mutating_methods_' + if kmm in clsdict: + mutating_methods = clsdict[kmm] + for base in bases: + methods = ( t for t in inspect.getmembers(base, inspect.ismethod) if not t[0].startswith("_") ) + for name, method in methods: + if name in clsdict: + continue + method_with_values = needs_values(method) + if name in mutating_methods: + method_with_values = set_dirty_and_flush_changes(method_with_values) + # END mutating methods handling + + clsdict[name] = method_with_values + # END for each name/method pair + # END for each base + # END if mutating methods configuration is set + + new_type = super(MetaParserBuilder, metacls).__new__(metacls, name, bases, clsdict) + return new_type + + + +def needs_values(func): + """Returns method assuring we read values (on demand) before we try to access them""" + def assure_data_present(self, *args, **kwargs): + self.read() + return func(self, *args, **kwargs) + # END wrapper method + assure_data_present.__name__ = func.__name__ + return assure_data_present + +def set_dirty_and_flush_changes(non_const_func): + """Return method that checks whether given non constant function may be called. + If so, the instance will be set dirty. + Additionally, we flush the changes right to disk""" + def flush_changes(self, *args, **kwargs): + rval = non_const_func(self, *args, **kwargs) + self.write() + return rval + # END wrapper method + flush_changes.__name__ = non_const_func.__name__ + return flush_changes + + +class SectionConstraint(object): + """Constrains a ConfigParser to only option commands which are constrained to + always use the section we have been initialized with. + + It supports all ConfigParser methods that operate on an option""" + __slots__ = ("_config", "_section_name") + _valid_attrs_ = ("get_value", "set_value", "get", "set", "getint", "getfloat", "getboolean", "has_option", + "remove_section", "remove_option", "options") + + def __init__(self, config, section): + self._config = config + self._section_name = section + + def __getattr__(self, attr): + if attr in self._valid_attrs_: + return lambda *args, **kwargs: self._call_config(attr, *args, **kwargs) + return super(SectionConstraint,self).__getattribute__(attr) + + def _call_config(self, method, *args, **kwargs): + """Call the configuration at the given method which must take a section name + as first argument""" + return getattr(self._config, method)(self._section_name, *args, **kwargs) + + @property + def config(self): + """return: Configparser instance we constrain""" + return self._config + + +class GitConfigParser(cp.RawConfigParser, object): + """Implements specifics required to read git style configuration files. + + This variation behaves much like the git.config command such that the configuration + will be read on demand based on the filepath given during initialization. + + The changes will automatically be written once the instance goes out of scope, but + can be triggered manually as well. + + The configuration file will be locked if you intend to change values preventing other + instances to write concurrently. + + :note: + The config is case-sensitive even when queried, hence section and option names + must match perfectly.""" + __metaclass__ = MetaParserBuilder + + + #{ Configuration + # The lock type determines the type of lock to use in new configuration readers. + # They must be compatible to the LockFile interface. + # A suitable alternative would be the BlockingLockFile + t_lock = LockFile + + #} END configuration + + OPTCRE = re.compile( + r'\s?(?P