From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 2AC791381F3 for ; Tue, 16 Jul 2013 16:36:05 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 69C46E0A87; Tue, 16 Jul 2013 16:36:03 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id EB3E1E0A87 for ; Tue, 16 Jul 2013 16:36:02 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id CF35E33E998 for ; Tue, 16 Jul 2013 16:36:01 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id F1015E5466 for ; Tue, 16 Jul 2013 16:35:58 +0000 (UTC) From: "André Erdmann" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "André Erdmann" Message-ID: <1373992529.07451ee1180548e6ed961142fb512a368a107e04.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/interface/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/interface/depres.py roverlay/interface/generic.py roverlay/interface/root.py X-VCS-Directories: roverlay/interface/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: 07451ee1180548e6ed961142fb512a368a107e04 X-VCS-Branch: gsoc13/next Date: Tue, 16 Jul 2013 16:35:58 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 0e7916c2-be36-484f-9bea-4ef00f256f53 X-Archives-Hash: 46128ac9ff6d5cb88d23b249c7e73750 Message-ID: <20130716163558.t1dkNcr519CHRtmGn0RU92ZMX7_abZpthIrZDxBTRnc@z> commit: 07451ee1180548e6ed961142fb512a368a107e04 Author: André Erdmann mailerd de> AuthorDate: Tue Jul 16 16:35:29 2013 +0000 Commit: André Erdmann mailerd de> CommitDate: Tue Jul 16 16:35:29 2013 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=07451ee1 roverlay/interface: in-code documentation --- roverlay/interface/depres.py | 186 +++++++++++++++++++++++++++++++++++++++++- roverlay/interface/generic.py | 68 +++++++++++++++ roverlay/interface/root.py | 50 ++++++++++++ 3 files changed, 303 insertions(+), 1 deletion(-) diff --git a/roverlay/interface/depres.py b/roverlay/interface/depres.py index e16363c..181243f 100644 --- a/roverlay/interface/depres.py +++ b/roverlay/interface/depres.py @@ -1,4 +1,4 @@ -# R overlay -- +# R overlay -- dependency resolution interface # -*- coding: utf-8 -*- # Copyright (C) 2013 André Erdmann # Distributed under the terms of the GNU General Public License; @@ -22,8 +22,28 @@ class RuleSyntaxException ( Exception ): pass class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): + """Interface to dependency resolution. + + This class provides: + + * rule creation (from text/text files) + * manage dependency rule pools (stack-like discard_pool()/get_new_pool()) + * resolve dependencies: + -> do_resolve() for "raw" depres results + -> resolve() for generic purpose results (list of resolved deps) + -> can_resolve()/cannot_resolve() for checking whether a + dependency string can(not) be resolved + + Note that this interface relies on a parent interface (RootInterface). + """ def __init__ ( self, parent_interface ): + """Initializes the depdency resolution interface. + + arguments: + * parent_interface -- parent interface that provides shared functionality + like logging and config + """ super ( DepresInterface, self ).__init__ ( parent_interface=parent_interface ) @@ -47,32 +67,49 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): @property def resolver ( self ): + """direct access to the resolver""" return self._resolver @property def parser ( self ): + """direct access to the rule parser""" return self._parser @property def poolstack ( self ): + """direct access to the dependency rule pool stack""" return self._poolstack @property def pool_id ( self ): + """Index of the topmost rule pool (-1 if no rule pool active)""" return self._pool_id def _update_resolver ( self ): + """Updates the resolver. + + Returns: None (implicit) + """ # sort() should be called on a per-pool basis self._resolver._reset_unresolvable() # --- end of _update_resolver (...) --- def close ( self ): + """Closes the dependency resolver and all subinterfaces. + + Returns: self + """ super ( DepresInterface, self ).close() self._resolver.close() return self # --- end of close (...) --- def update ( self ): + """Updates this interface, i.e. performs a "soft"-reload of the + resolver and sorts the topmost rule pool. + + Returns: self + """ super ( DepresInterface, self ).update() if self._poolstack: self._poolstack[-1].sort() @@ -81,18 +118,32 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of update (...) --- def fixup_pool_id ( self ): + """Resets the pool id. + + Does not need to be called manually. + + Returns: None (implicit) + """ self._pool_id = len ( self._poolstack ) - 1 # --- end of fixup_pool_id (...) --- def has_pool ( self ): + """ + Returns True if this interface has at least one rule pool, else False. + """ return self._poolstack # --- end of has_pool (...) --- def has_nonempty_pool ( self ): + """ + Returns True if the topmost rule pool of this interface exists + and is not empty. + """ return self._poolstack and not self._poolstack[-1].empty() # --- end of has_nonempty_pool (...) --- def get_pool ( self ): + """Returns the topmost rule pool. Creates one if necessary.""" if self._poolstack: return self._poolstack[-1] else: @@ -100,6 +151,13 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of get_pool (...) --- def get_new_pool ( self, force=False, with_deptype=DEFAULT_DEPTYPE ): + """Creates a new pool, adds it to the pool stack and returns it. + + arguments: + * force -- if True: force creation of a new pool even if the + current one is empty + * with_deptype -- dependency type of the new pool (optional) + """ if force or not self._poolstack or not self._poolstack[-1].empty(): self._pool_id += 1 try: @@ -118,6 +176,10 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of get_new_pool (...) --- def discard_pool ( self ): + """Discards the topmost rule pool. + + Returns: True if a pool has been removed, else False. + """ try: self._poolstack.pop() self._pool_id -= 1 @@ -130,6 +192,13 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of discard_pool (...) --- def discard_pools ( self, count ): + """Discards up to rule pools. + + arguments: + * count -- number of rule pool to remove + + Returns: number of rule pool that have been removed (<= count) + """ for i in range ( count ): if not self.discard_pool(): return i @@ -138,6 +207,10 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of discard_pools (...) --- def discard_all_pools ( self ): + """Discards all rule pools. + + Returns: number of removed rule pools + """ i = 0 while self.discard_pool(): i += 1 @@ -145,6 +218,10 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of discard_all_pools (...) --- def discard_empty_pools ( self ): + """Discards rule pools until the topmost one is not empty. + + Returns: number of removed rule pools + """ removed = 0 while self._poolstack and self._poolstack[-1].empty(): if self.discard_pool(): @@ -157,6 +234,14 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of discard_empty_pools (...) --- def load_rules_from_config ( self, ignore_missing=False ): + """Loads all configured rule files into a new pool (or new pools). + + arguments: + * ignore_missing -- if True: do not raise an Exception if + SIMPLE_RULE_FILE is not set in the config + + Returns: True if rule files have been loaded, else False. + """ if ignore_missing: rule_files = self.config.get ( "DEPRES.simple_rules.files", None ) if rule_files: @@ -170,30 +255,70 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of load_rules_from_config (...) --- def load_rule_files ( self, files_or_dirs ): + """Loads the given files into a new rule pool (or new pools). + + Returns: True on success, else False + """ ret = self._resolver.get_reader().read ( files_or_dirs ) self.fixup_pool_id() return ret # --- end of load_rule_files (...) --- def add_rule ( self, rule_str ): + """Sends a text line to the rule parser. + + arguments: + * rule_str -- text line + + Returns: True + + Raises: RuleSyntaxException if rule_str cannot be parsed + + Note: rules have to be compiled via compile_rules() after adding + text lines + """ if not self._parser.add ( rule_str ): raise RuleSyntaxException ( rule_str ) return True # --- end of add_rule (...) --- def add_rules ( self, *rule_str_list ): + """Sends several text lines to the rule parser. + See add_rule() for details. + + arguments: + * *rule_str_list -- + + Returns: True + """ for rule_str in rule_str_list: self.add_rule ( rule_str ) return True # --- end of add_rules (...) --- def add_rule_list ( self, rule_str_list ): + """Like add_rules(), but accepts a single list-like arg. + See add_rule()/add_rules() for details. + + arguments: + * rule_str_list -- + + Returns: True + """ for rule_str in rule_str_list: self.add_rule ( rule_str ) return True # --- end of add_rule_list (...) --- def compile_rules ( self, new_pool=False ): + """Tells the rule parser to 'compile' rules. This converts the text + input into dependency rule objects, which are then added to a rule pool. + + arguments: + * new_pool -- create a new pool for the compiled rules + + Returns: True + """ rules = self._parser.done() destpool = self.get_new_pool() if new_pool else self.get_pool() @@ -218,10 +343,24 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of compile_rules (...) --- def add_immediate_rule ( self, rule_str ): + """Directly adds a single rule (given in rule file syntax form) to + the topmost rule pool. + + arguments: + * rule_str -- text line + + Note: this method calls compile_rules(), which creates rule objects + for all text lines added so far. + + Returns: True + """ return self.add_rule ( rule_str ) and self.compile_rules() # --- end of add_immediate_rule (...) --- def visualize_pool ( self ): + """Visualizes the topmost rule pool. This returns a string that contains + all rules of this pool in text form (in rule file syntax). + """ if self._poolstack: return '\n'.join ( '\n'.join ( rule.export_rule() ) @@ -232,6 +371,15 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of visualize_pool (...) --- def get_channel ( self, channel_name="channel" ): + """Creates, registers and returns an EbuildJobChannel suitable for + dependency resolution. + + Note: This doesn't need to be called manually in order to resolve + dependencies. + + arguments: + * channel_name -- name of the channel (defaults to "channel") + """ channel = roverlay.depres.channels.EbuildJobChannel ( err_queue=self.err_queue, name=channel_name ) @@ -240,6 +388,17 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of get_channel (...) --- def do_resolve ( self, deps, with_deptype=DEFAULT_DEPTYPE ): + """Performs dependency resolution for the given dependency list and + returns the result, which is None (=not resolved) or a 2-tuple + (, ). + + Note: use resolve() for resolving dependencies unless the 2-tuple + result form is desired. + + arguments: + * deps -- dependency string list + * with_deptype -- dependency type (optional, defaults to DEFAULT_DEPTYPE) + """ channel = self.get_channel() # FIXME/COULDFIX: once again, hardcoded deptype try: @@ -256,15 +415,40 @@ class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ): # --- end of do_resolve (...) --- def resolve ( self, *deps, **kw ): + """Like do_resolve(), but accepts the dependency string list in var-args + form and returns None (=not resolved) or a list of resolved dependencies. + + arguments: + * *deps -- list of dependency strings + * **kw -- passed to do_resolve() + """ result = self.do_resolve ( deps, **kw ) + # result := ( list, list ) return None if result is None else result [0] # --- end of resolve (...) --- def can_resolve ( self, *deps, **kw ): + """Like resolve(), but simply returns True if all dependencies could + be resolved. + + Technically, returns True IFF all mandatory dependencies could be + resolved. + + arguments: + * *deps -- + * **kw -- + """ return self.do_resolve ( deps, **kw ) is not None # --- end of can_resolve (...) --- def cannot_resolve ( self, *deps, **kw ): + """Like can_resolve(), but returns True if at least one (mandatory) + dependency could not be resolved. + + arguments: + * *deps -- + * **kw -- + """ return self.do_resolve ( deps, **kw ) is None # --- end of cannot_resolve (...) --- diff --git a/roverlay/interface/generic.py b/roverlay/interface/generic.py index c6678f3..b86cc31 100644 --- a/roverlay/interface/generic.py +++ b/roverlay/interface/generic.py @@ -7,28 +7,53 @@ #import weakref class RoverlayInterface ( object ): + """Base class for roverlay interfaces. + Provides functionality for attaching/detaching subinterfaces. + """ def __init__ ( self ): + """Initializes this interfaces.""" super ( RoverlayInterface, self ).__init__() self._interfaces = dict() # --- end of __init__ (...) --- def close_interfaces ( self ): + """Closes all subinterfaces.""" if hasattr ( self, '_interfaces' ): for iface in self._interfaces.values(): iface.close() # --- end of close_interfaces (...) --- def close ( self ): + """Closes this interfaces and all of its subinterfaces. + + Returns: self + """ self.close_interfaces() return self # --- end of close (...) --- def update ( self ): + """Updates this interface. + + Does nothing. Derived classes may implement it. + + Returns: self + """ return self # --- end of update (...) --- def attach_interface ( self, name, interface, close_detached=True ): + """Adds a subinterface. + + arguments: + * name -- name of the interface + * interface -- interface object to add + * close_detached -- if an interface with the same name has been replaced + by the new one: close it if True + + Returns: added interface + """ if name in self._interfaces: self.detach ( name, close=close_detached ) @@ -37,6 +62,14 @@ class RoverlayInterface ( object ): # --- end of attach_interface (...) --- def detach_interface ( self, name, close=False ): + """Detaches an interface. + + arguments: + * name -- name of the interface + * close -- close interface after detaching it + + Returns: detached interface if close is False, else True + """ detached = self._interfaces [name] del self._interfaces [name] if close: @@ -47,14 +80,40 @@ class RoverlayInterface ( object ): # --- end of detach_interface (...) --- def get_interface ( self, name ): + """Provides access to a subinterface by name. + + arguments: + * name -- name of the interface + + Returns: interface (object) + + Raises: KeyError if interface does not exist + """ return self._interfaces [name] # --- end of get_interface (...) --- def has_interface ( self, name ): + """Returns True if a subinterface with the given name exists, else False. + + arguments: + * name -- name of the interface + """ return name and name in self._interfaces # --- end of has_interface (...) --- def __getattr__ ( self, name ): + """ Provides alternative access to subinterfaces via + ._interface + + arguments: + * name -- attribute name + + Returns: interface if name ends with '_interface' + + Raises: KeyError if name ends with '_interface' and the referenced + interface does not exist + """ + if name [-10:] == '_interface': iface_name = name [:-10] if iface_name and iface_name in self._interfaces: @@ -66,8 +125,17 @@ class RoverlayInterface ( object ): # --- end of RoverlayInterface --- class RoverlaySubInterface ( RoverlayInterface ): + """Base class derived from RoverlayInterface for interfaces that have + a parent interface. + """ def __init__ ( self, parent_interface ): + """Initializes the subinterface. Creates references to shared objects + like logger and config as well as a ref to the parent interface. + + arguments: + * parent_interface -- + """ super ( RoverlaySubInterface, self ).__init__() # weakref? (would require to explicitly keep "parent" instances around) self.parent = parent_interface diff --git a/roverlay/interface/root.py b/roverlay/interface/root.py index a4d287c..c571eea 100644 --- a/roverlay/interface/root.py +++ b/roverlay/interface/root.py @@ -16,11 +16,26 @@ import roverlay.interface.generic roverlay.setup_initial_logger() class RootInterface ( roverlay.interface.generic.RoverlayInterface ): + """Root interfaces for accessing roverlay interfaces. + See MainInterface for a root interface with delayed initialization. + """ + + # class-wide map ( => ) + # for creating/"spawning" subinterfaces + # SPAWN_MAP = dict() @classmethod def register_interface ( my_cls, name, cls, force=False ): + """Registers a subinterface with the root interface. + + arguments: + * name -- name of the interface, e.g. "depres" + * cls -- interface class + * force -- if True: overwrite existing entries for name + Defaults to False. + """ if name and ( force or name not in my_cls.SPAWN_MAP ): my_cls.SPAWN_MAP [name] = cls return True @@ -31,6 +46,19 @@ class RootInterface ( roverlay.interface.generic.RoverlayInterface ): def __init__ ( self, config_file=None, config=None, additional_config=None, is_installed=None ): + """Initializes the root interface: + * loads the config + * creates shared objects like logger and error queue + * calls roverlay.hook.setup() + + arguments: + * config_file -- path to the config file + * config -- config tree or None + takes precedence over config_file + * additional_config -- when loading the config file: extra config dict + * is_installed -- whether roverlay has been installed or not + Defaults to None. + """ super ( RootInterface, self ).__init__() self.parent = None self.err_queue = roverlay.errorqueue.ErrorQueue() @@ -66,10 +94,25 @@ class RootInterface ( roverlay.interface.generic.RoverlayInterface ): # --- end of __init__ (...) --- def set_installed ( self, status=True ): + """Marks roverlay as installed/not installed. + + arguments: + * status -- installation status bool (defaults to True) + + Returns: None (implicit) + """ self.config.merge_with ( { 'installed': bool ( status ), } ) # --- end of set_installed (...) --- def spawn_interface ( self, name ): + """Spawns an registered subinterface. + (Creates it if necessary, else uses the existing one.) + + arguments: + * name -- name of the interface, e.g. "depres" + + Returns: subinterface + """ if self.has_interface ( name ): return self.get_interface ( name ) else: @@ -85,5 +128,12 @@ class RootInterface ( roverlay.interface.generic.RoverlayInterface ): # --- end of spawn_interface (...) --- def run_hook ( self, phase ): + """Triggers a hook event. + + arguments: + * phase -- event, e.g. "overlay_success" or "user" + + Returns: success (True/False) + """ return roverlay.hook.run ( phase, catch_failure=False ) # --- end of run_hook (...) ---