aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Erdmann <dywi@mailerd.de>2013-07-16 18:35:29 +0200
committerAndré Erdmann <dywi@mailerd.de>2013-07-16 18:35:29 +0200
commit07451ee1180548e6ed961142fb512a368a107e04 (patch)
tree81721bcd40b1605963784fec4934b792094dec26
parentroverlay/remote: print repo name while syncing (diff)
downloadR_overlay-07451ee1180548e6ed961142fb512a368a107e04.tar.gz
R_overlay-07451ee1180548e6ed961142fb512a368a107e04.tar.bz2
R_overlay-07451ee1180548e6ed961142fb512a368a107e04.zip
roverlay/interface: in-code documentation
-rw-r--r--roverlay/interface/depres.py186
-rw-r--r--roverlay/interface/generic.py68
-rw-r--r--roverlay/interface/root.py50
3 files changed, 303 insertions, 1 deletions
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 <dywi@mailerd.de>
# 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(<deps>) for "raw" depres results
+ -> resolve(<deps>) for generic purpose results (list of resolved deps)
+ -> can_resolve(<deps>)/cannot_resolve(<deps>) 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 <count> 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
+ (<resolved deps>, <unresolvable, but optional deps>).
+
+ 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<resolved>, list<unresolvable> )
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
+ <self>.<subinterface name>_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 ( <interface name> => <interface class> )
+ # 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 (...) ---