]> Savannah Git Hosting - gnulib.git/commitdiff
[pygnulib] BaseConfig, CachedConfig and Module classes (sketches)
authorDmitry Selyutin <ghostmansd@gmail.com>
Mon, 21 Aug 2017 20:17:41 +0000 (23:17 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Mon, 21 Aug 2017 20:17:41 +0000 (23:17 +0300)
pygnulib/config.py [new file with mode: 0644]
pygnulib/module.py [new file with mode: 0644]

diff --git a/pygnulib/config.py b/pygnulib/config.py
new file mode 100644 (file)
index 0000000..faf39fd
--- /dev/null
@@ -0,0 +1,206 @@
+#!/usr/bin/python
+# encoding: UTF-8
+
+
+import codecs
+import os
+import re
+
+
+class GenericConfig:
+    """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"           : "",
+        "lib"               : "libgnu",
+        "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,
+        "libtool"           : False,
+        "conddeps"          : False,
+        "vc-files"          : False,
+        "autoconf"          : 2.59,
+        "modules"           : [],
+        "avoids"            : [],
+        "files"             : [],
+    }
+
+
+    def __repr__(self):
+        return "pygnulib.GenericConfig" + str(self._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 __getitem__(self, key):
+        if key not in GenericConfig._TABLE_:
+            key = key.replace("_", "-")
+            if key not in GenericConfig._TABLE_:
+                raise KeyError("unsupported option: '%s'" % key)
+        return self._table_[key]
+
+
+    def __setitem__(self, key, value):
+        if key not in GenericConfig._TABLE_:
+            key = key.replace("_", "-")
+            if key not in GenericConfig._TABLE_:
+                raise KeyError("unsupported option: '%s'" % key)
+
+        typeid = type(GenericConfig._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)")
+        elif key == "autoconf":
+            if value < 2.59:
+                raise NotImplementedError("pygnulib ")
+        elif not isinstance(value, typeid):
+            raise TypeError("'%s' option must be of '%s' type" % (key, typeid))
+
+        tests = ["tests", "cxx-tests", "longrunning-tests", "privileged-tests", "unportable-tests"]
+        if key == "all-tests":
+            for _ in tests:
+                self._table_[_] = value
+        else:
+            self._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."""
+    _AUTOCONF_ = {
+        "autoconf" : re.compile(".*AC_PREREQ\\(\\[(.*?)\\]\\)", re.S | re.M),
+        "aux-dir"  : re.compile("^AC_CONFIG_AUX_DIR\\(\\[(.*?)\\]\\)$", re.S | re.M),
+        "libtool"  : re.compile("A[CM]_PROG_LIBTOOL", re.S | re.M)
+    }
+    _GNULIB_CACHE_ = {
+        "libtool"           : (bool, "gl_LIBTOOL"),
+        "conddeps"          : (bool, "gl_CONDITIONAL_DEPENDENCIES"),
+        "vc-files"          : (bool, "gl_VC_FILES"),
+        "tests"             : (bool, "gl_WITH_TESTS"),
+        "obsolete"          : (bool, "gl_WITH_OBSOLETE"),
+        "cxx-tests"         : (bool, "gl_WITH_CXX_TESTS"),
+        "longrunning-tests" : (bool, "gl_WITH_LONGRUNNING_TESTS"),
+        "privileged-tests"  : (bool, "gl_WITH_PRIVILEGED_TESTS"),
+        "unportable-tests"  : (bool, "gl_WITH_UNPORTABLE_TESTS"),
+        "all-tests"         : (bool, "gl_WITH_ALL_TESTS"),
+        "local-dir"         : (str, "gl_LOCAL_DIR"),
+        "source-base"       : (str, "gl_SOURCE_BASE"),
+        "m4-base"           : (str, "gl_M4_BASE"),
+        "po-base"           : (str, "gl_PO_BASE"),
+        "doc-base"          : (str, "gl_DOC_BASE"),
+        "tests-base"        : (str, "gl_TESTS_BASE"),
+        "makefile-name"     : (str, "gl_MAKEFILE_NAME"),
+        "macro-prefix"      : (str, "gl_MACRO_PREFIX"),
+        "po-domain"         : (str, "gl_PO_DOMAIN"),
+        "witness-c-macro"   : (str, "gl_WITNESS_C_MACRO"),
+        "lib"               : (str, "gl_LIB"),
+        "modules"           : (list, "gl_MODULES"),
+        "avoids"            : (list, "gl_AVOID"),
+        "lgpl"              : (str, "gl_LGPL"),
+    }
+    _GNULIB_CACHE_BOOL_ = []
+    _GNULIB_CACHE_STR_ = []
+    _GNULIB_CACHE_LIST_ = []
+    for _key_, (_typeid_, _) in _GNULIB_CACHE_.items():
+        if _typeid_ is bool:
+            _GNULIB_CACHE_BOOL_ += [_key_]
+        elif _typeid_ is str:
+            _GNULIB_CACHE_STR_ += [_key_]
+        else:
+            _GNULIB_CACHE_LIST_ += [_key_]
+    _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 _autoconf_(self, autoconf):
+        root = self["root"]
+        if not autoconf:
+            autoconf = os.path.join(root, "configure.ac")
+            if not os.path.exists(autoconf):
+                autoconf = os.path.join(root, "configure.in")
+        if not os.path.isabs(autoconf):
+            autoconf = os.path.join(root, autoconf)
+        with codecs.open(autoconf, "rb", "UTF-8") as stream:
+            data = stream.read()
+        for key, pattern in CachedConfig._AUTOCONF_.items():
+            match = pattern.findall(data)
+            if not match:
+                continue
+            if key == "autoconf":
+                self["autoconf"] = sorted(set([float(_.strip()) for _ in match if _.strip()]))[-1]
+            else:
+                self[key] = match[-1]
+
+    def _gnulib_cache_(self):
+        root = self["root"]
+        m4base = self["m4-base"]
+        gnulib_cache = os.path.join(root, m4base, "gnulib-cache.m4")
+        if os.path.exists(gnulib_cache):
+            with codecs.open(gnulib_cache, "rb", "UTF-8") as stream:
+                data = stream.read()
+            for key in CachedConfig._GNULIB_CACHE_BOOL_:
+                (_, macro) = CachedConfig._GNULIB_CACHE_[key]
+                if key in data:
+                    self[key] = True
+            match = dict(CachedConfig._GNULIB_CACHE_PATTERN_.findall(data))
+            for key in CachedConfig._GNULIB_CACHE_STR_:
+                (_, macro) = CachedConfig._GNULIB_CACHE_[key]
+                if macro in match:
+                    self[key] = match[macro].strip()
+            for key in CachedConfig._GNULIB_CACHE_LIST_:
+                (_, macro) = CachedConfig._GNULIB_CACHE_[key]
+                if macro in match:
+                    self[key] = [_.strip() for _ in match[macro].split("\n") if _.strip()]
+
+    def _gnulib_comp_(self):
+        root = self["root"]
+        m4base = self["m4-base"]
+        gnulib_comp = os.path.join(root, m4base, "gnulib-comp.m4")
+        if os.path.exists(gnulib_comp):
+            with codecs.open(gnulib_comp, "rb", "UTF-8") as stream:
+                data = stream.read()
+            regex = "AC_DEFUN\\(\\[%s_FILE_LIST\\], \\[(.*?)\\]\\)" % self["macro-prefix"]
+            pattern = re.compile(regex, re.S | re.M)
+            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_)
diff --git a/pygnulib/module.py b/pygnulib/module.py
new file mode 100644 (file)
index 0000000..8fd168b
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+# encoding: UTF-8
+
+
+import os
+import re
+import codecs
+
+
+class Module:
+    _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"),
+        "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"),
+        "include"       : (0x0A, list, None, "Include"),
+        "link"          : (0x0B, list, None, "Link"),
+        "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)
+
+
+    def __init__(self):
+        self._table_ = dict()
+
+
+    def __getitem__(self, key):
+        if key not in Module._TABLE_:
+            raise ValueError("unsupported key: '%s'" % key)
+        return self._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._table_[key] = value
+
+
+    @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
+
+
+    @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 package(self):
+        result = ""
+        for key, (_, typeid, _, field) in sorted(Module._TABLE_.items(), key=lambda k: k[1][0]):
+            field += ":\n"
+            if typeid is list:
+                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"