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)")
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),
_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):
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):
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):
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_)
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"
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()