]> Savannah Git Hosting - gnulib.git/commitdiff
config: autoconf options; version match; cleanup
authorDmitry Selyutin <ghostmansd@gmail.com>
Wed, 17 Jan 2018 18:25:50 +0000 (21:25 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Wed, 17 Jan 2018 18:28:21 +0000 (21:28 +0300)
pygnulib.py
pygnulib/config.py
pygnulib/parser.py

index fa32be283f82d4e1d708f855b1ac93c7d03a5ed8..f66290791601139cd41b00e9dbb793073edc17aa 100755 (executable)
@@ -96,7 +96,7 @@ def extract_hook(program, gnulib, mode, namespace, *args, **kwargs):
 def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args, **kwargs):
     (_, _) = (args, kwargs)
     config = BaseConfig(**namespace)
-    cache = CachedConfig(configure=None)
+    cache = CachedConfig(root=config.root)
     for key in {"ac_version", "files"}:
         if key not in namespace:
             config[key] = cache[key]
index 7eef86bcf036cdbbcc4e14a07aaf2f4962be6a36..546c804ce7e7206642fa820841751bc821442436 100644 (file)
@@ -7,7 +7,9 @@
 import codecs as _codecs
 import os as _os
 import re as _re
+
 from collections import OrderedDict as _OrderedDict
+from distutils import version as _version
 
 
 from .error import type_assert as _type_assert
@@ -56,42 +58,47 @@ class BaseConfig:
         "po_domain"         : "",
         "witness_c_macro"   : "",
         "licenses"          : set(),
-        "libtool"           : False,
-        "conditionals"      : True,
-        "vc_files"          : False,
-        "ac_version"        : 2.59,
+        "ac_version"        : "2.59",
+        "ac_file"           : "configure.ac",
         "modules"           : set(),
         "avoids"            : set(),
         "files"             : set(),
         "copymode"          : None,
         "local_copymode"    : None,
+        "tests"             : False,
+        "obsolete"          : False,
+        "cxx_tests"         : False,
+        "longrunning_tests" : False,
+        "privileged_tests"  : False,
+        "unportable_tests"  : False,
+        "libtool"           : False,
+        "conditionals"      : True,
+        "copyrights"        : False,
         "gnumake"           : False,
+        "single_configure"  : False,
+        "vc_files"          : False,
     }
-    _OPTIONS = frozenset({
-        "tests",
-        "obsolete",
-        "cxx_tests",
-        "longrunning_tests",
-        "privileged_tests",
-        "unportable_tests",
-    })
 
 
     class _Option:
         """gnulib configuration options"""
-        Obsolete = (1 << 0)
-        Tests = (1 << 1)
+        Tests = (1 << 0)
+        Obsolete = (1 << 1)
         CXX = (1 << 2)
         Longrunning = (1 << 3)
         Privileged = (1 << 4)
         Unportable = (1 << 5)
-        Copyrights = (1 << 6)
-        GNUMake = (1 << 7)
-        AllTests = (Obsolete | Tests | CXX | Longrunning | Privileged | Unportable | GNUMake)
+        Libtool = (1 << 6)
+        Conditionals = (1 << 7)
+        Copyrights = (1 << 8)
+        GNUMake = (1 << 9)
+        SingeConfigure = (1 << 10)
+        AllTests = (Obsolete | Tests | CXX | Longrunning | Privileged | Unportable)
 
 
     def __init__(self, **kwargs):
-        self.__table = {"options": 0}
+        self.__options = 0
+        self.__table = {}
         for (key, value) in BaseConfig._TABLE.items():
             self[key] = kwargs.get(key, value)
 
@@ -102,10 +109,6 @@ class BaseConfig:
         return "{}.{}{}".format(module, name, repr(self.__table))
 
 
-    def __iter__(self):
-        return iter(self.__table)
-
-
     def __enter__(self):
         return self
 
@@ -303,270 +306,297 @@ class BaseConfig:
         self.__table["licenses"] = frozenset(result)
 
 
+    @property
+    def ac_version(self):
+        """minimal supported autoconf version"""
+        return self.__table["ac_version"]
+
+    @ac_version.setter
+    def ac_version(self, value):
+        _type_assert("ac_version", value, str)
+        if _version.LooseVersion(value) < _version.LooseVersion("2.59"):
+            raise _AutoconfVersionError("2.59")
+        self.__table["ac_version"] = value
+
+
+    @property
+    def ac_file(self):
+        """autoconf file (usually configure.ac or configure.in)"""
+        return self.__table["ac_file"]
+
+    @ac_file.setter
+    def ac_file(self, value):
+        _type_assert("ac_file", value, str)
+        self.__table["ac_file"] = value
+
+
+    @property
+    def modules(self):
+        """list of modules"""
+        return self.__table["modules"]
+
+    @modules.setter
+    def modules(self, value):
+        _type_assert("modules", value, _ITERABLES)
+        result = set()
+        for item in value:
+            _type_assert("module", item, str)
+            result.add(item)
+        self.__table["modules"] = frozenset(result)
+
+
+    @property
+    def avoids(self):
+        """list of modules to avoid"""
+        return self.__table["avoids"]
+
+    @avoids.setter
+    def avoids(self, value):
+        _type_assert("avoids", value, _ITERABLES)
+        result = set()
+        for item in value:
+            _type_assert("avoid", item, str)
+            result.add(item)
+        self.__table["avoids"] = frozenset(result)
+
+
+    @property
+    def files(self):
+        """list of files to be processed"""
+        return self.__table["files"]
+
+    @files.setter
+    def files(self, value):
+        _type_assert("files", value, _ITERABLES)
+        result = set()
+        for item in value:
+            _type_assert("file", item, str)
+            result.add(item)
+        self.__table["files"] = frozenset(result)
+
+
+    @property
+    def include_guard_prefix(self):
+        """include guard prefix"""
+        prefix = self.__table["macro_prefix"].upper()
+        default = BaseConfig._TABLE["macro_prefix"].upper()
+        return "GL" if prefix == default else "GL_{0}".format(prefix)
+
+
+    @property
+    def copymode(self):
+        """file copy mode ('symlink', 'hardlink' or None)"""
+        return self.__table["copymode"]
+
+    @copymode.setter
+    def copymode(self, value):
+        if value not in frozenset({None, "symlink", "hardlink"}):
+            raise ValueError("copymode: None, 'symlink' or 'hardlink'")
+        self.__table["copymode"] = value
+
+
+    @property
+    def local_copymode(self):
+        """file copy mode for local directory ('symlink', 'hardlink' or None)"""
+        return self.__table["local_copymode"]
+
+    @local_copymode.setter
+    def local_copymode(self, value):
+        if value not in frozenset({None, "symlink", "hardlink"}):
+            raise ValueError("local_copymode: None, 'symlink' or 'hardlink'")
+        self.__table["local_copymode"] = value
+
+
     @property
     def tests(self):
-        """include unit tests for the included modules"""
-        return bool(self.__table["options"] & BaseConfig._Option.Tests)
+        """include unit tests for the included modules?"""
+        return bool(self.__options & BaseConfig._Option.Tests)
 
     @tests.setter
     def tests(self, value):
         _type_assert("tests", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Tests
+            self.__options |= BaseConfig._Option.Tests
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Tests
+            self.__options &= ~BaseConfig._Option.Tests
 
 
     @property
     def obsolete(self):
-        """include obsolete modules when they occur among the modules"""
-        return bool(self.__table["options"] & BaseConfig._Option.Tests)
+        """include obsolete modules when they occur among the modules?"""
+        return bool(self.__options & BaseConfig._Option.Tests)
 
     @obsolete.setter
     def obsolete(self, value):
         _type_assert("obsolete", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Obsolete
+            self.__options |= BaseConfig._Option.Obsolete
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Obsolete
+            self.__options &= ~BaseConfig._Option.Obsolete
 
 
     @property
     def cxx_tests(self):
-        """include even unit tests for C++ interoperability"""
-        return bool(self.__table["options"] & BaseConfig._Option.CXX)
+        """include even unit tests for C++ interoperability?"""
+        return bool(self.__options & BaseConfig._Option.CXX)
 
     @cxx_tests.setter
     def cxx_tests(self, value):
         _type_assert("cxx_tests", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.CXX
+            self.__options |= BaseConfig._Option.CXX
         else:
-            self.__table["options"] &= ~BaseConfig._Option.CXX
+            self.__options &= ~BaseConfig._Option.CXX
 
 
     @property
     def longrunning_tests(self):
-        """include even unit tests that are long-runners"""
-        return bool(self.__table["options"] & BaseConfig._Option.Longrunning)
+        """include even unit tests that are long-runners?"""
+        return bool(self.__options & BaseConfig._Option.Longrunning)
 
     @longrunning_tests.setter
     def longrunning_tests(self, value):
         _type_assert("longrunning_tests", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Longrunning
+            self.__options |= BaseConfig._Option.Longrunning
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Longrunning
+            self.__options &= ~BaseConfig._Option.Longrunning
 
 
     @property
     def privileged_tests(self):
-        """include even unit tests that require root privileges"""
-        return bool(self.__table["options"] & BaseConfig._Option.Privileged)
+        """include even unit tests that require root privileges?"""
+        return bool(self.__options & BaseConfig._Option.Privileged)
 
     @privileged_tests.setter
     def privileged_tests(self, value):
         _type_assert("privileged_tests", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Privileged
+            self.__options |= BaseConfig._Option.Privileged
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Privileged
+            self.__options &= ~BaseConfig._Option.Privileged
 
 
     @property
     def unportable_tests(self):
-        """include even unit tests that fail on some platforms"""
-        return bool(self.__table["options"] & BaseConfig._Option.Unportable)
+        """include even unit tests that fail on some platforms?"""
+        return bool(self.__options & BaseConfig._Option.Unportable)
 
     @unportable_tests.setter
     def unportable_tests(self, value):
         _type_assert("unportable_tests", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Unportable
+            self.__options |= BaseConfig._Option.Unportable
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Unportable
+            self.__options &= ~BaseConfig._Option.Unportable
 
 
     @property
     def all_tests(self):
-        """include all kinds of problematic unit tests"""
-        return (self.__table["options"] & BaseConfig._Option.AllTests) == BaseConfig._Option.AllTests
+        """include all kinds of problematic unit tests?"""
+        return (self.__options & BaseConfig._Option.AllTests) == BaseConfig._Option.AllTests
 
     @all_tests.setter
     def all_tests(self, value):
         if value:
-            self.__table["options"] |= BaseConfig._Option.AllTests
+            self.__options |= BaseConfig._Option.AllTests
         else:
-            self.__table["options"] &= BaseConfig._Option.AllTests
+            self.__options &= BaseConfig._Option.AllTests
 
 
     @property
     def libtool(self):
-        """use libtool rules"""
-        return self.__table["libtool"]
+        """use libtool rules?"""
+        return bool(self.__options & BaseConfig._Option.Libtool)
 
     @libtool.setter
     def libtool(self, value):
         _type_assert("libtool", value, bool)
-        self.__table["libtool"] = value
+        if value:
+            self.__options |= BaseConfig._Option.Libtool
+        else:
+            self.__options &= ~BaseConfig._Option.Libtool
 
 
     @property
     def conditionals(self):
-        """support conditional dependencies (may save configure time and object code)"""
-        return self.__table["conditionals"]
+        """support conditional dependencies (may save configure time and object code)?"""
+        return bool(self.__options & BaseConfig._Option.Conditionals)
 
     @conditionals.setter
     def conditionals(self, value):
         _type_assert("conditionals", value, bool)
-        self.__table["conditionals"] = value
-
-
-    @property
-    def vc_files(self):
-        """update version control related files"""
-        return self.__table["vc_files"]
-
-    @vc_files.setter
-    def vc_files(self, value):
-        _type_assert("vc_files", value, bool)
-        self.__table["vc_files"] = value
-
-
-    @property
-    def ac_version(self):
-        """minimal supported autoconf version"""
-        return self.__table["ac_version"]
-
-    @ac_version.setter
-    def ac_version(self, value):
-        if isinstance(value, str):
-            value = float(value)
-        _type_assert("ac_version", value, float)
-        if value < 2.59:
-            raise _AutoconfVersionError(2.59)
-        self.__table["ac_version"] = value
-
-
-    @property
-    def modules(self):
-        """list of modules"""
-        return self.__table["modules"]
-
-    @modules.setter
-    def modules(self, value):
-        _type_assert("modules", value, _ITERABLES)
-        result = set()
-        for item in value:
-            _type_assert("module", item, str)
-            result.add(item)
-        self.__table["modules"] = frozenset(result)
-
-
-    @property
-    def avoids(self):
-        """list of modules to avoid"""
-        return self.__table["avoids"]
-
-    @avoids.setter
-    def avoids(self, value):
-        _type_assert("avoids", value, _ITERABLES)
-        result = set()
-        for item in value:
-            _type_assert("avoid", item, str)
-            result.add(item)
-        self.__table["avoids"] = frozenset(result)
-
-
-    @property
-    def files(self):
-        """list of files to be processed"""
-        return self.__table["files"]
-
-    @files.setter
-    def files(self, value):
-        _type_assert("files", value, _ITERABLES)
-        result = set()
-        for item in value:
-            _type_assert("file", item, str)
-            result.add(item)
-        self.__table["files"] = frozenset(result)
-
-
-    @property
-    def include_guard_prefix(self):
-        """include guard prefix"""
-        prefix = self.__table["macro_prefix"].upper()
-        default = BaseConfig._TABLE["macro_prefix"].upper()
-        return "GL" if prefix == default else "GL_{0}".format(prefix)
-
-
-    @property
-    def copymode(self):
-        """file copy mode ('symlink', 'hardlink' or None)"""
-        return self.__table["copymode"]
-
-    @copymode.setter
-    def copymode(self, value):
-        if value not in frozenset({None, "symlink", "hardlink"}):
-            raise ValueError("copymode: None, 'symlink' or 'hardlink'")
-        self.__table["copymode"] = value
+        if value:
+            self.__options |= BaseConfig._Option.Conditionals
+        else:
+            self.__options &= ~BaseConfig._Option.Conditionals
 
 
     @property
-    def local_copymode(self):
-        """file copy mode for local directory ('symlink', 'hardlink' or None)"""
-        return self.__table["local_copymode"]
+    def copyrights(self):
+        """update the license copyright text?"""
+        return bool(self.__options & BaseConfig._Option.Copyrights)
 
-    @local_copymode.setter
-    def local_copymode(self, value):
-        if value not in frozenset({None, "symlink", "hardlink"}):
-            raise ValueError("local_copymode: None, 'symlink' or 'hardlink'")
-        self.__table["local_copymode"] = value
+    @copyrights.setter
+    def copyrights(self, value):
+        _type_assert("copyrights", value, bool)
+        if value:
+            self.__options |= BaseConfig._Option.Copyrights
+        else:
+            self.__options &= ~BaseConfig._Option.Copyrights
 
 
     @property
     def gnumake(self):
-        """update the license copyright text"""
-        return bool(self.__table["options"] & BaseConfig._Option.GNUMake)
+        """update the license copyright text?"""
+        return bool(self.__options & BaseConfig._Option.GNUMake)
 
     @gnumake.setter
     def gnumake(self, value):
         _type_assert("gnumake", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.GNUMake
+            self.__options |= BaseConfig._Option.GNUMake
         else:
-            self.__table["options"] &= ~BaseConfig._Option.GNUMake
+            self.__options &= ~BaseConfig._Option.GNUMake
 
 
     @property
-    def copyrights(self):
-        """update the license copyright text"""
-        return bool(self.__table["options"] & BaseConfig._Option.Copyrights)
+    def single_configure(self):
+        """generate a single configure file?"""
+        return bool(self.__options & BaseConfig._Option.SingeConfigure)
 
-    @copyrights.setter
-    def copyrights(self, value):
-        _type_assert("copyrights", value, bool)
+    @single_configure.setter
+    def single_configure(self, value):
+        _type_assert("single_configure", value, bool)
         if value:
-            self.__table["options"] |= BaseConfig._Option.Copyrights
+            self.__options |= BaseConfig._Option.SingeConfigure
         else:
-            self.__table["options"] &= ~BaseConfig._Option.Copyrights
+            self.__options &= ~BaseConfig._Option.SingeConfigure
+
+
+    @property
+    def vc_files(self):
+        """update version control related files?"""
+        return self.__table["vc_files"]
+
+    @vc_files.setter
+    def vc_files(self, value):
+        _type_assert("vc_files", value, bool)
+        self.__table["vc_files"] = value
 
 
     def __getitem__(self, key):
-        table = (set(BaseConfig._TABLE.keys()) | BaseConfig._OPTIONS)
-        if key not in table:
+        if key not in BaseConfig._TABLE:
             key = key.replace("-", "_")
-            if key not in table:
+            if key not in BaseConfig._TABLE:
                 raise KeyError("unsupported option: {0}".format(key))
         return getattr(self, key)
 
 
     def __setitem__(self, key, value):
-        table = (set(BaseConfig._TABLE.keys()) | BaseConfig._OPTIONS)
-        if key not in table:
+        if key not in BaseConfig._TABLE:
             key = key.replace("_", "-")
-            if key not in table:
+            if key not in BaseConfig._TABLE:
                 raise KeyError("unsupported option: {0}".format(key))
         return setattr(self, key, value)
 
@@ -592,8 +622,8 @@ class CachedConfig(BaseConfig):
     _COMMENTS = _compile(r"((?:(?:#)|(?:^dnl\s+)|(?:\s+dnl\s+)).*?)$")
     _AUTOCONF = {
         "ac_version" : _compile(r"AC_PREREQ\(\[(.*?)\]\)"),
-        "auxdir"   : _compile(r"AC_CONFIG_AUX_DIR\(\[(.*?)\]\)$"),
-        "libtool"  : _compile(r"A[CM]_PROG_LIBTOOL")
+        "auxdir"     : _compile(r"AC_CONFIG_AUX_DIR\(\[(.*?)\]\)$"),
+        "libtool"    : _compile(r"A[CM]_PROG_LIBTOOL")
     }
     _GNULIB_CACHE = {
         "overrides"         : (list, _compile(r"gl_LOCAL_DIR\(\[(.*?)\]\)")),
@@ -623,35 +653,32 @@ class CachedConfig(BaseConfig):
     }
 
 
-    def __init__(self, configure=None, **kwargs):
-        super().__init__(**kwargs)
-        if configure is None:
-            configure = _os.path.join(self.root, "configure.ac")
-            if not _os.path.exists(configure):
-                configure = _os.path.join(self.root, "configure.in")
-        if not _os.path.isabs(configure):
-            configure = _os.path.join(self.root, configure)
-        kwargs = {"configure": _os.path.normpath(configure), "explicit": tuple(kwargs.keys())}
-        calls = (self.__configure_ac, self.__gnulib_cache, self.__gnulib_comp)
-        for call in calls:
-            try:
-                call(**kwargs)
-            except FileNotFoundError:
-                pass # ignore non-existent files
-
-
-    def __configure_ac(self, configure, explicit, **kwargs):
-        with _codecs.open(configure, "rb", "UTF-8") as stream:
+    def __init__(self, root, ac_file=None, **kwargs):
+        if ac_file is None:
+            ac_file = "configure.ac"
+        _type_assert("ac_file", ac_file, str)
+        ac_path = _os.path.join(root, ac_file)
+        if not _os.path.exists(ac_path):
+            ac_file = "configure.in"
+            ac_path = _os.path.join(root, ac_file)
+        ac_path = _os.path.normpath(ac_path)
+        super().__init__(root=root, **kwargs)
+        self.__autoconf(ac_path, kwargs)
+        self.__gnulib_cache(kwargs)
+        self.__gnulib_comp(kwargs)
+
+
+    def __autoconf(self, ac_path, explicit):
+        with _codecs.open(ac_path, "rb", "UTF-8") as stream:
             data = CachedConfig._COMMENTS.sub("", stream.read())
         for (key, pattern) in CachedConfig._AUTOCONF.items():
             match = pattern.findall(data)
             if match and key not in explicit:
                 self[key] = match[-1]
 
-    def __gnulib_cache(self, explicit, **kwargs):
-        m4_base = self.m4_base
+    def __gnulib_cache(self, explicit):
+        expected_m4_base = self.m4_base
         path = _os.path.join(self.root, self.m4_base, "gnulib-cache.m4")
-        path = _os.path.normpath(path)
         if not _os.path.exists(path):
             raise FileNotFoundError(path)
         with _codecs.open(path, "rb", "UTF-8") as stream:
@@ -673,13 +700,12 @@ class CachedConfig(BaseConfig):
                 else:
                     sep = None if key == "overrides" else "\n"
                     self[key] = [_.strip() for _ in match[-1].split(sep) if _.strip()]
-        if m4_base != self.m4_base:
-            raise _M4BaseMismatchError(path, m4_base, self.m4_base)
+        if expected_m4_base != self.m4_base:
+            raise _M4BaseMismatchError(path, expected_m4_base, self.m4_base)
 
-    def __gnulib_comp(self, explicit, **kwargs):
+    def __gnulib_comp(self, explicit):
         macro_prefix = self.macro_prefix
         path = _os.path.join(self.root, self.m4_base, "gnulib-comp.m4")
-        path = _os.path.normpath(path)
         if not _os.path.exists(path):
             raise FileNotFoundError(path)
         with _codecs.open(path, "rb", "UTF-8") as stream:
index b46d061e32080c2656573c209075cb72a30ac4a8..505933dcfc16c0500033260701dc49044abba301 100644 (file)
@@ -897,12 +897,6 @@ class CommandLine:
         return "\n".join(lines).format(program=self.__program)
 
 
-    class Option:
-        """option bitwise flags"""
-        DryRun = (1 << 0)
-        SingleConfigure = (1 << 1)
-
-
     def __init__(self, program):
         self.__parser = _argparse.ArgumentParser(prog=program, add_help=False)
         for (options, kwargs) in CommandLine._SECTIONS_[0][2]:
@@ -958,6 +952,5 @@ class CommandLine:
         verbosity = namespace.pop("verbosity", 0)
         options = dict(namespace)
         options.setdefault("dry_run", False)
-        options.setdefault("single_configure", False)
         namespace["overrides"] = list(reversed(namespace.get("overrides", [])))
         return (namespace, mode, verbosity, options)