from pygnulib.error import UnknownModuleError
from pygnulib.config import Base as BaseConfig
from pygnulib.config import Cache as CacheConfig
-from pygnulib.module import Table as ModuleTable
+from pygnulib.module import transitive_closure
from pygnulib.parser import CommandLine as CommandLineParser
from pygnulib.filesystem import GnulibGit as GnulibGitFS
def import_hook(gnulib, namespace, verbosity, options, *args, **kwargs):
(_, _) = (args, kwargs)
config = BaseConfig(**namespace)
- table = ModuleTable(gnulib.module, config.modules, config.options)
+ values = transitive_closure(gnulib.module, config.modules, config.options)
+ (base, full, main, final, tests) = transitive_closure(gnulib.module, config.modules, config.options)
+ # Print some information about modules.
print("Module list with included dependencies (indented):", file=sys.stdout)
BOLD_ON = BOLD_OFF = ""
mode = os.fstat(sys.stdout.fileno()).st_mode
if not (stat.S_ISFIFO(mode) or stat.S_ISREG(mode)):
BOLD_ON = "\033[1m"
BOLD_OFF = "\033[0m"
- for module in sorted(table.final):
+ for module in sorted(final):
manual = module.name in config.modules
prefix = " " if manual else " "
bold_on = BOLD_ON if manual else ""
bold_off = BOLD_OFF if manual else ""
print("{0}{1}{2}{3}".format(prefix, bold_on, module.name, bold_off), file=sys.stdout)
-
if verbosity >= 1:
print("Main module list:", file=sys.stdout)
- for module in sorted(table.main):
+ for module in sorted(main):
print(" {0}".format(module.name), file=sys.stdout)
-
print("Tests-related module list:", file=sys.stdout)
- for module in sorted(table.tests):
+ for module in sorted(tests):
print(" {0}".format(module.name), file=sys.stdout)
return os.EX_OK
-class Table:
- """module transitive closure result"""
- def __init__(self, lookup, modules, options):
- """
- Perform a transitive closure, generating a set of module dependencies.
- Each iteration over the table yields a tuple of (module, demander, condition).
-
- If condition is None, but demander is not, there is no special condition for this module.
- If demander is None, the module is provided unconditionally (condition is always None).
-
- lookup must be a callable which obtains a pygnulib module by its name.
- modules is an iterable, yielding a module (either name or instance).
- options may be any combination of gnulib configuration options.
- """
- if not callable(lookup):
- raise TypeError("lookup must be a callable")
- _type_assert_("options", options, int)
- if options & ~_ConfigOption_.All:
- raise ValueError("unknown configuration options")
-
- obsolete = bool(options & _ConfigOption_.Obsolete)
- tests = bool(options & _ConfigOption_.Tests)
- cxx_tests = bool(options & _ConfigOption_.CXX)
- longrunning_tests = bool(options & _ConfigOption_.Longrunning)
- privileged_tests = bool(options & _ConfigOption_.Privileged)
- unportable_tests = bool(options & _ConfigOption_.Unportable)
- modules = set(lookup(module) for module in modules)
-
- def _transitive_closure_(tests):
- queue = set()
- previous = set()
- current = set()
- for module in modules:
- current.add((module, None, None))
- while previous != current:
- previous.update(current)
- for (demander, _, _) in previous:
- if demander in queue:
- continue
- if tests and not demander.name.endswith("-tests"):
- try:
- name = "{0}-tests".format(demander.name)
- current.add((lookup(name), None, None))
- except _UnknownModuleError_:
- pass # ignore non-existent tests
- for (dependency, condition) in demander.dependencies:
- module = lookup(dependency)
- exclude = (
- (not obsolete and module.obsolete),
- (not cxx_tests and module.cxx_test),
- (not longrunning_tests and module.longrunning_test),
- (not privileged_tests and module.privileged_test),
- (not unportable_tests and module.unportable_test),
- )
- if not any(exclude):
- condition = condition if condition.strip() else None
- current.add((module, demander, condition))
- queue.add(demander)
- return current
-
- self.__with_tests = tests
- self.__base = _transitive_closure_(False)
- self.__full = _transitive_closure_(True)
-
-
- def __iter__(self):
- return iter(self.__full)
-
-
- @property
- def main(self):
- """an iterator over main module set"""
- return iter(set(module for (module, _, _) in self.__base))
-
-
- @property
- def tests(self):
- """an iterator over tests-related module set"""
- final = self.final
- if not self.__with_tests:
- final = (module for module in final if module.applicability != "all")
- main = (module for module in self.main if module.applicability != "all")
- return iter(set(final) ^ set(main))
-
-
- @property
- def final(self):
- """an iterator over final module set"""
- return self.all if self.__with_tests else self.main
-
-
- @property
- def all(self):
- """an iterator over all modules"""
- return iter(set(module for (module, _, _) in self.__full))
+def transitive_closure(lookup, modules, options):
+ """
+ Perform a transitive closure, generating a set of module dependencies.
+ Each iteration over the table yields a tuple of (module, demander, condition).
+
+ If condition is None, but demander is not, there is no special condition for this module.
+ If demander is None, the module is provided unconditionally (condition is always None).
+
+ lookup must be a callable which obtains a pygnulib module by its name.
+ modules is an iterable, yielding a module (either name or instance).
+ options may be any combination of gnulib configuration options.
+ """
+ if not callable(lookup):
+ raise TypeError("lookup must be a callable")
+ _type_assert_("options", options, int)
+ if options & ~_ConfigOption_.All:
+ raise ValueError("unknown configuration options")
+
+ obsolete = bool(options & _ConfigOption_.Obsolete)
+ tests = bool(options & _ConfigOption_.Tests)
+ cxx_tests = bool(options & _ConfigOption_.CXX)
+ longrunning_tests = bool(options & _ConfigOption_.Longrunning)
+ privileged_tests = bool(options & _ConfigOption_.Privileged)
+ unportable_tests = bool(options & _ConfigOption_.Unportable)
+ modules = set(lookup(module) for module in modules)
+
+ def _transitive_closure_(tests):
+ queue = set()
+ previous = set()
+ current = set()
+ for module in modules:
+ current.add((module, None, None))
+ while previous != current:
+ previous.update(current)
+ for (demander, _, _) in previous:
+ if demander in queue:
+ continue
+ if tests and not demander.name.endswith("-tests"):
+ try:
+ name = "{0}-tests".format(demander.name)
+ current.add((lookup(name), None, None))
+ except _UnknownModuleError_:
+ pass # ignore non-existent tests
+ for (dependency, condition) in demander.dependencies:
+ module = lookup(dependency)
+ exclude = (
+ (not obsolete and module.obsolete),
+ (not cxx_tests and module.cxx_test),
+ (not longrunning_tests and module.longrunning_test),
+ (not privileged_tests and module.privileged_test),
+ (not unportable_tests and module.unportable_test),
+ )
+ if not any(exclude):
+ condition = condition if condition.strip() else None
+ current.add((module, demander, condition))
+ queue.add(demander)
+ return current
+
+ base = _transitive_closure_(False)
+ full = _transitive_closure_(True)
+ main = set(module for (module, _, _) in base)
+ final = set(module for (module, _, _) in full) if tests else set(main)
+ tests_final = set(module for module in final if not tests or module.applicability != "all")
+ tests_main = set(module for module in main if module.applicability != "all")
+ tests = (tests_final ^ tests_main)
+ return (base, full, main, final, tests)