]> Savannah Git Hosting - gnulib.git/commitdiff
[pygnulib] properties support; file-like module class
authorDmitry Selyutin <ghostmansd@gmail.com>
Tue, 22 Aug 2017 20:54:22 +0000 (23:54 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Tue, 22 Aug 2017 20:54:22 +0000 (23:54 +0300)
pygnulib/config.py
pygnulib/module.py

index faf39fdf39c39918f150a6f4f0029a6cb67c4566..b8cbf50aed8a9fd0fe34cc47411df034683670b8 100644 (file)
@@ -7,73 +7,73 @@ import os
 import re
 
 
-class GenericConfig:
+class Config:
     """The most basic gnulib configuration holder"""
     _TABLE_ = {
         "gnulib"            : "",
         "root"              : "",
-        "local-dir"         : "",
-        "source-base"       : "lib",
-        "m4-base"           : "m4",
-        "po-base"           : "po",
-        "doc-base"          : "doc",
-        "tests-base"        : "tests",
-        "aux-dir"           : "",
+        "local_dir"         : "",
+        "source_base"       : "lib",
+        "m4_base"           : "m4",
+        "po_base"           : "po",
+        "doc_base"          : "doc",
+        "tests_base"        : "tests",
+        "aux_dir"           : "",
         "lib"               : "libgnu",
-        "makefile-name"     : "Makefile.am",
-        "macro-prefix"      : "gl",
-        "po-domain"         : "",
-        "witness-c-macro"   : "",
+        "makefile_name"     : "Makefile.am",
+        "macro_prefix"      : "gl",
+        "po_domain"         : "",
+        "witness_c_macro"   : "",
         "lgpl"              : 0,
         "tests"             : False,
-        "cxx-tests"         : False,
-        "longrunning-tests" : False,
-        "privileged-tests"  : False,
-        "unportable-tests"  : False,
-        "all-tests"         : False,
+        "cxx_tests"         : False,
+        "longrunning_tests" : False,
+        "privileged_tests"  : False,
+        "unportable_tests"  : False,
+        "all_tests"         : False,
         "libtool"           : False,
         "conddeps"          : False,
-        "vc-files"          : False,
+        "vc_files"          : False,
         "autoconf"          : 2.59,
-        "modules"           : [],
-        "avoids"            : [],
-        "files"             : [],
     }
 
 
     def __repr__(self):
-        return "pygnulib.GenericConfig" + str(self._table_)
+        return repr(self.__dict__["_table_"])
 
 
-    def __init__(self, gnulib, root, **kwargs):
-        if not (os.path.isdir(gnulib) and os.path.isdir(os.path.join(gnulib, ".git"))):
-            raise NotADirectoryError(gnulib)
-        if not os.path.isdir(root):
-            raise NotADirectoryError(gnulib)
-        self._table_ = dict()
-        for arg in GenericConfig._TABLE_:
-            self._table_[arg] = GenericConfig._TABLE_[arg]
-        self._table_["gnulib"] = gnulib
-        self._table_["root"] = root
-        for arg in kwargs:
-            self[arg] = kwargs[arg]
+    def __init__(self, **kwargs):
+        self.__dict__["_table_"] = dict()
+        for key in Config._TABLE_:
+            self.__dict__["_table_"][key] = Config._TABLE_[key]
+        for key, value in kwargs.items():
+            self[key] = value
+
+
+    def __setattr__(self, key, value):
+        self[key] = value
+        self.__dict__[key] = value
+
+
+    def __getattr__(self, key):
+        return self[key]
 
 
     def __getitem__(self, key):
-        if key not in GenericConfig._TABLE_:
+        if key not in Config._TABLE_:
             key = key.replace("_", "-")
-            if key not in GenericConfig._TABLE_:
+            if key not in Config._TABLE_:
                 raise KeyError("unsupported option: '%s'" % key)
-        return self._table_[key]
+        return self.__dict__["_table_"][key]
 
 
     def __setitem__(self, key, value):
-        if key not in GenericConfig._TABLE_:
+        if key not in Config._TABLE_:
             key = key.replace("_", "-")
-            if key not in GenericConfig._TABLE_:
+            if key not in Config._TABLE_:
                 raise KeyError("unsupported option: '%s'" % key)
 
-        typeid = type(GenericConfig._TABLE_[key])
+        typeid = type(Config._TABLE_[key])
         if key == "lgpl":
             if value not in [None, 2, 3]:
                 raise TypeError("lgpl option must be either None or integral version (2 or 3)")
@@ -86,18 +86,14 @@ class GenericConfig:
         tests = ["tests", "cxx-tests", "longrunning-tests", "privileged-tests", "unportable-tests"]
         if key == "all-tests":
             for _ in tests:
-                self._table_[_] = value
+                self.__dict__["_table_"][_] = value
         else:
-            self._table_[key] = value
+            self.__dict__["_table_"][key] = value
 
 
-    def path(path):
-        path = os.path.normpath(path)
-        os.path.split(os.path.sep)
 
-
-class CachedConfig(GenericConfig):
-    """Unlike GenericConfig, CachedConfig tries to retrieve variables from the cached files."""
+class CachedConfig(Config):
+    """Cached configuration holder"""
     _AUTOCONF_ = {
         "autoconf" : re.compile(".*AC_PREREQ\\(\\[(.*?)\\]\\)", re.S | re.M),
         "aux-dir"  : re.compile("^AC_CONFIG_AUX_DIR\\(\\[(.*?)\\]\\)$", re.S | re.M),
@@ -142,14 +138,15 @@ class CachedConfig(GenericConfig):
     _GNULIB_CACHE_PATTERN_ = re.compile("^(gl_.*?)\\(\\[(.*?)\\]\\)$", re.S | re.M)
 
 
-    def __init__(self, gnulib, root, autoconf=None, **kwargs):
-        super(CachedConfig, self).__init__(gnulib, root, **kwargs)
-        self._autoconf_(autoconf)
-        self._gnulib_cache_()
-        self._gnulib_comp_()
+    def __init__(self, root, autoconf=None, **kwargs):
+        if not isinstance(root, str):
+            raise TypeError("root must be of 'str' type")
+        super(CachedConfig, self).__init__(**kwargs)
+        self._autoconf_(root, autoconf)
+        self._gnulib_cache_(root)
+        self._gnulib_comp_(root)
 
-    def _autoconf_(self, autoconf):
-        root = self["root"]
+    def _autoconf_(self, root, autoconf):
         if not autoconf:
             autoconf = os.path.join(root, "configure.ac")
             if not os.path.exists(autoconf):
@@ -167,8 +164,7 @@ class CachedConfig(GenericConfig):
             else:
                 self[key] = match[-1]
 
-    def _gnulib_cache_(self):
-        root = self["root"]
+    def _gnulib_cache_(self, root):
         m4base = self["m4-base"]
         gnulib_cache = os.path.join(root, m4base, "gnulib-cache.m4")
         if os.path.exists(gnulib_cache):
@@ -188,8 +184,7 @@ class CachedConfig(GenericConfig):
                 if macro in match:
                     self[key] = [_.strip() for _ in match[macro].split("\n") if _.strip()]
 
-    def _gnulib_comp_(self):
-        root = self["root"]
+    def _gnulib_comp_(self, root):
         m4base = self["m4-base"]
         gnulib_comp = os.path.join(root, m4base, "gnulib-comp.m4")
         if os.path.exists(gnulib_comp):
@@ -200,7 +195,3 @@ class CachedConfig(GenericConfig):
             match = pattern.findall(data)
             if match:
                 self["files"] = [_.strip() for _ in match[-1].split("\n") if _.strip()]
-
-
-    def __repr__(self):
-        return "pygnulib.CachedConfig" + str(self._table_)
index 8fd168be274bb0aacc64d5a0abb1891db015ce23..69824f1176e2652fd4070e67535759d90f92efb1 100644 (file)
@@ -7,79 +7,58 @@ import re
 import codecs
 
 
+
 class Module:
+    _PATTERN_ = re.compile("")
     _TABLE_ = {
-        "description"   : (0x00,  str, None, "Description"),
-        "comment"       : (0x01,  str, None, "Comment"),
-        "status"        : (0x02,  str, None, "Status"),
-        "notice"        : (0x03,  str, None, "Notice"),
-        "applicability" : (0x04,  str, None, "Applicability"),
+        "description"   : (0x00, str, None, "Description"),
+        "comment"       : (0x01, str, None, "Comment"),
+        "status"        : (0x02, str, None, "Status"),
+        "notice"        : (0x03, str, None, "Notice"),
+        "applicability" : (0x04, str, None, "Applicability"),
         "files"         : (0x05, list, None, "Files"),
         "dependencies"  : (0x06, list, None, "Depends-on"),
-        "preconfigure"  : (0x07,  str, None, "configure.ac-early"),
-        "configure"     : (0x08,  str, None, "configure.ac"),
-        "makefile"      : (0x09,  str, None, "Makefile.am"),
+        "preconfigure"  : (0x07, str, None, "configure.ac-early"),
+        "configure"     : (0x08, str, None, "configure.ac"),
+        "makefile"      : (0x09, str, None, "Makefile.am"),
         "include"       : (0x0A, list, None, "Include"),
         "link"          : (0x0B, list, None, "Link"),
-        "license"       : (0x0C,  str, None, "License"),
+        "license"       : (0x0C, str, None, "License"),
         "maintainers"   : (0x0D, list, None, "Maintainer"),
     }
-    _EXCLUDE_ = {
-        "CVS",
-        "ChangeLog",
-        "COPYING",
-        "README",
-        "TEMPLATE",
-        "TEMPLATE-EXTENDED",
-    }
-    for key, (uid, typeid, _, field) in _TABLE_.items():
-        suffix = ("(?:" + ":|".join([_[3] for _ in _TABLE_.values()]) + ":)")
-        pattern = re.compile(("^%s:\\s*(.*?)%s" % (field, suffix)), re.S | re.M)
-        _TABLE_[key] = (uid, typeid, pattern, field)
+    for _key_, (_uid_, _typeid_, _, _field_) in _TABLE_.items():
+        _suffix_ = ("(?:" + ":|".join([_[3] for _ in _TABLE_.values()]) + ":)")
+        _pattern_ = re.compile(("^%s:\\s*(.*?)%s" % (_field_, _suffix_)), re.S | re.M)
+        _TABLE_[_key_] = (_uid_, _typeid_, _pattern_, _field_)
 
 
-    def __init__(self):
-        self._table_ = dict()
+    def __init__(self, name, **kwargs):
+        if not isinstance(name, str):
+            raise TypeError("name must be of 'str' type")
+        self.__dict__["_name_"] = name
+        self.__dict__["_table_"] = dict()
+        for key in Module._TABLE_:
 
-
-    def __getitem__(self, key):
-        if key not in Module._TABLE_:
-            raise ValueError("unsupported key: '%s'" % key)
-        return self._table_[key]
+            self.__dict__["_table_"][key] = ""
+        self.__dict__["_table_"]["maintainers"] = ["all"]
+        for key, value in kwargs.items():
+            self[key] = value
 
 
-    def __setitem__(self, key, value):
-        if key not in Module._TABLE_:
-            raise ValueError("unsupported key: '%s'" % key)
-        typeid = Module._TABLE_[key][1]
-        if not isinstance(value, typeid):
-            raise TypeError("'%s' key expects '%s' type" % (key, typeid))
-        self._table_[key] = value
+    @property
+    def name(self):
+        return self.__dict__["_name_"]
 
 
-    @classmethod
-    def file(cls, path):
-        module = Module()
-        with codecs.open(path, "rb", "UTF-8") as stream:
-            data = stream.read()
-        for key, (_, typeid, pattern, field) in Module._TABLE_.items():
-            match = pattern.findall(data)
-            if typeid is list:
-                module[key] = [_ for _ in "".join(match).split("\n") if _.strip()]
-            else:
-                module[key] = "\n".join([_.strip() for _ in match]) if match else ""
-        return module
+    def __hash__(self):
+        return hash(str(self))
 
 
-    @classmethod
-    def list(cls, config):
-        base = os.path.join(config["gnulib"], "modules")
-        for root, _, files in os.walk(base):
-            for file in [_ for _ in files if _ not in Module._EXCLUDE_]:
-                yield file
+    def __repr__(self):
+        return self.__dict__["_name_"]
 
 
-    def package(self):
+    def __str__(self):
         result = ""
         for key, (_, typeid, _, field) in sorted(Module._TABLE_.items(), key=lambda k: k[1][0]):
             field += ":\n"
@@ -87,10 +66,106 @@ class Module:
                 value = "\n".join(self[key])
             else:
                 value = self[key]
-            if key == "maintainers" and not value:
-                value = "all"
             if value:
                 result += field
                 result += value
                 result += "\n\n" if value else "\n"
         return result.strip() + "\n"
+
+
+    def __setattr__(self, key, value):
+        self[key] = value
+        self.__dict__[key] = value
+
+
+    def __getattr__(self, key):
+        return self[key]
+
+
+    def __getitem__(self, key):
+        if key not in Module._TABLE_:
+            raise ValueError("unsupported key: '%s'" % key)
+        return self.__dict__["_table_"][key]
+
+
+    def __setitem__(self, key, value):
+        if key not in Module._TABLE_:
+            raise ValueError("unsupported key: '%s'" % key)
+        typeid = Module._TABLE_[key][1]
+        if not isinstance(value, typeid):
+            raise TypeError("'%s' key expects '%s' type" % (key, typeid))
+        self.__dict__["_table_"][key] = value
+
+
+    def __lt__(self, value):
+        if isinstance(value, Module):
+            return (self != value) and (self.__dict__["_name_"] < value.name)
+        return TypeError("cannot compare pygnulib.Module with %r type" % type(value))
+
+    def __le__(self, value):
+        return self.__lt__(value) or self.__eq__(value)
+
+    def __eq__(self, value):
+        if isinstance(value, Module):
+            return (self.__dict__["_name_"] == value.__dict__["_name_"]) \
+                and (self.__dict__["_table_"] == value.__dict__["_name_"])
+        return TypeError("cannot compare pygnulib.Module with %r type" % type(value))
+
+    def __ne__(self, value):
+        return not self.__eq__(value)
+
+    def __ge__(self, value):
+        if isinstance(value, Module):
+            return value.__le__(self)
+        return TypeError("cannot compare pygnulib.Module with %r type" % type(value))
+
+    def __gt__(self, value):
+        if isinstance(value, Module):
+            return value.__lt__(self)
+        return TypeError("cannot compare pygnulib.Module with %r type" % type(value))
+
+
+
+class FileModule(Module):
+    """Read or modify existing gnulib module package"""
+
+    def __init__(self, path, mode="r", name=None, **kwargs):
+        if name is None:
+            name = os.path.basename(path)
+        if mode not in ("r", "w", "rw"):
+            raise ValueError("illegal mode: %r" % mode)
+        if mode == "r":
+            super(FileModule, self).__init__(name)
+            with codecs.open(path, "rb", "UTF-8") as stream:
+                data = stream.read()
+            for key, (_, typeid, pattern, _) in Module._TABLE_.items():
+                match = pattern.findall(data)
+                self[key] = [_ for _ in "".join(match).split("\n") if _.strip()] \
+                            if typeid is list else \
+                            ("\n".join([_.strip() for _ in match]) if match else "")
+            self.__dict__["_stream_"] = None
+        elif mode == "w":
+            super(FileModule, self).__init__(name)
+            self.__dict__["_stream_"] = codecs.open(path, "w+", "UTF-8")
+        elif mode == "rw":
+            self.__init__(path, "r")
+            self.__dict__["_stream_"] = codecs.open(path, "w+", "UTF-8")
+        else:
+            raise ValueError("invalid mode: %r" % mode)
+        for key, value in kwargs.items():
+            self[key] = value
+
+
+    def close(self):
+        if self.__dict__["_stream_"]:
+            self.__dict__["_stream_"].truncate(0)
+            self.__dict__["_stream_"].write(str(self))
+            self.__dict__["_stream_"].close()
+
+
+    def __enter__(self):
+        return self
+
+
+    def __exit__(self, exctype, excval, exctrace):
+        self.close()