From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
Date: Thu, 19 Sep 2013 15:00:36 +0000 (UTC) [thread overview]
Message-ID: <1379602803.daefc87c578f6b8a4b7bd903c40a1d84adbead37.dywi@gentoo> (raw)
commit: daefc87c578f6b8a4b7bd903c40a1d84adbead37
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 19 15:00:03 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 19 15:00:03 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=daefc87c
roverlay/setupscript/hookenv: comments, cleanup
---
roverlay/setupscript/hookenv.py | 544 +++++++++++++++++++++++++++++++++-------
1 file changed, 453 insertions(+), 91 deletions(-)
diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index d361801..212d041 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -19,6 +19,9 @@ import roverlay.setupscript.baseenv
class HookOverwriteControl ( object ):
+ """Object for deciding whether a file/link/... is allowed to be
+ overwritten by a hook link."""
+
OV_NONE = 0
OV_SYM_DEAD = 2**0
OV_SYM_EXIST = 2**1
@@ -35,16 +38,37 @@ class HookOverwriteControl ( object ):
@classmethod
def from_str ( cls, vstr ):
+ """Returns a new instance representing one of the control modes from
+ OV_KEYWORDS.
+
+ arguments:
+ * vstr --
+ """
return cls ( cls.OV_KEYWORDS[vstr] )
# --- end of from_str (...) ---
def __init__ ( self, value ):
+ """HookOverwriteControl constructor.
+
+ arguments:
+ * value -- the control mode (has to be an int, usually a comibination of
+ the OV_* masks provided by the HookOverwriteControl class)
+ """
super ( HookOverwriteControl, self ).__init__()
assert isinstance ( value, int ) and value >= 0
self.value = value
# --- end of __init__ (...) ---
def can_overwrite ( self, mask=None ):
+ """Returns whether the control mode allows to overwrite files/links
+ with the given mask.
+
+ The return value should be interpreted in boolean context, but can
+ be an int.
+
+ arguments:
+ * mask --
+ """
if mask is None:
return self.value == self.OV_NONE
else:
@@ -52,15 +76,21 @@ class HookOverwriteControl ( object ):
# --- end of can_overwrite (...) ---
def overwrite_dead_symlinks ( self ):
+ """Returns whether overwriting of dangling/broken symlinks is allowed."""
return self.value & self.OV_SYM_DEAD
def overwrite_symlinks ( self ):
+ """Returns whether overwriting of arbitrary symlinks is allowed."""
return self.value & self.OV_SYM
def overwrite_all ( self ):
+ """Returns True if the control mode does not restrict overwriting,
+ else False."""
return self.value == self.OV_ALL
def get_str ( self ):
+ """Returns a string representation of the control mode suitable for
+ printing."""
value = self.value
def gen_words():
if value == self.OV_NONE:
@@ -87,6 +117,7 @@ class HookOverwriteControl ( object ):
class HookScriptBase ( roverlay.util.objects.Referenceable ):
+ """A hook script."""
CACHE_REF = True
@@ -99,7 +130,9 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
* fspath -- absolute path to the hook script
* filename -- name of the hook script
Defaults to os.path.basename(fspath).
- * priority -- priority of the hook script. Defaults to auto-detect.
+ * priority -- priority of the hook script.
+ Defaults to None (no priority).
+ Passing True as priority enables filename-based detection.
* is_hidden -- whether the script is "hidden" or not. Defaults to False.
"""
super ( HookScriptBase, self ).__init__()
@@ -132,11 +165,12 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
def __str__ ( self ):
yesno = lambda k: 'y' if k else 'n'
+
return "<{cls} {name!r}, hidden={h} prio={p}>".format (
- cls=self.__class__.__name__,
- name=self.name,
- h=yesno ( self.is_hidden ),
- p=(
+ cls = self.__class__.__name__,
+ name = self.name,
+ h = yesno ( self.is_hidden ),
+ p = (
"auto" if self.priority is None else
( "IGNORE" if self.priority < 0 else self.priority )
),
@@ -144,66 +178,46 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
# --- end of __str__ (...) ---
def has_priority ( self ):
+ """Returns True if this hook script has a valid priority."""
return self.priority is not None and self.priority >= 0
# --- end of has_priority (...) ---
- def set_priority ( self, priority, only_if_unset=True ):
- if self.priority is None:
- self.priority = priority
- elif self.priority < 0:
- raise Exception (
- "cannot assign priority to script with priority < 0."
- )
- elif not only_if_unset:
- self.priority = priority
- # --- end of set_priority (...) ---
-
- def get_static_info ( self ):
- return roverlay.static.hookinfo.get ( self.name, None )
- # --- end of get_static_info (...) ---
-
def is_visible ( self ):
+ """Returns True if this hook script can be used for linking/...,
+ else False."""
return not self.is_hidden and (
self.priority is None or self.priority >= 0
)
# --- end of is_visible (...) ---
- @roverlay.util.objects.abstractmethod
- def get_hookscript ( self ):
- pass
- # --- end of get_hookscript (...) ---
-
- @roverlay.util.objects.abstractmethod
- def get_hookscript_path ( self ):
- pass
- # --- end of get_hookscript_path (...) ---
-
- def get_dest_name ( self, file_ext='.sh', digit_len=2 ):
- # file_ext has to be .sh, else the script doesn't get recognized
- # by mux.sh
-
- prio = self.priority
- if prio is not None:
- if prio < 0:
- raise AssertionError ( "hook script has no priority." )
-
- return "{prio:0>{l}d}-{fname}{f_ext}".format (
- prio=prio, fname=self.name, f_ext=file_ext, l=digit_len,
- )
- else:
- return self.filename
- # --- end of get_dest_name (...) ---
-
# --- end of HookScriptBase ---
class UserHookScript ( HookScriptBase ):
+ """A hook script that resides in the user's hook script dir."""
@classmethod
def create_for_hook (
cls, hook, destdir, event_name, priority_gen,
file_ext='.sh', digit_len=2
):
+ """Creates a UserHookScript instance that can be used for linking
+ a HookScript in the given directory.
+
+ arguments:
+ * hook -- HookScript object
+ * destdir -- directory where the link to the HookScript will be
+ created
+ * event_name -- name of the event (usually basename of destdir)
+ * priority_gen -- priority generator (or an int) which will be used
+ if the HookScript object doesn't provide a priority
+ * file_ext -- file extension of the link name. Defautls to '.sh',
+ which shouldn't be changed, because the "mux.sh"
+ script recognizes file with this extension only.
+ * digit_len -- digit length of the priority part of the file name.
+ ("d^{>=digit_len}-{hook name}{file_ext}")
+ Defaults to 2.
+ """
if type ( priority_gen ) == int:
prio = priority_gen
elif hook.has_priority():
@@ -227,6 +241,17 @@ class UserHookScript ( HookScriptBase ):
# --- end of create_for_hook (...) ---
def __init__ ( self, fspath, filename=None, event=None, priority=True ):
+ """UserHookScript constructor.
+
+ arguments:
+ * fspath -- absolute path to the hook script
+ * filename -- name of the hook script
+ Defaults to os.path.basename(fspath).
+ * event -- name of the event to which this script belongs to,
+ e.g. "overlay_success" (or None). Defaults to None.
+ * priority -- priority of the hook script.
+ Defaults to True (auto-detect).
+ """
super ( UserHookScript, self ).__init__ (
fspath, filename=filename, priority=priority
)
@@ -237,12 +262,21 @@ class UserHookScript ( HookScriptBase ):
):
self.hook_script_ref = None
else:
+ # False means that this UserHookScript is not a link
self.hook_script_ref = False
self.event = event
# --- end of __init__ (...) ---
def set_hookscript ( self, script_obj, strict=True ):
+ """Assigns a HookScript to this UserHookScript. Also establishes
+ a back-reference in the hook script.
+
+ arguments:
+ * script_obj -- HookScript object
+ * strict -- whether to fail if this UserHookScript is not a link
+ (True) or not (False). Defaults to True.
+ """
if strict and script_obj and self.hook_script_ref is False:
raise Exception (
"user hook script {} is not a link!".format ( self.fspath )
@@ -256,13 +290,26 @@ class UserHookScript ( HookScriptBase ):
# --- end of set_hookscript (...) ---
def has_hookscript ( self ):
+ """Returns whether this object has a hook script of any kind (either
+ a HookScript object or a file)."""
return self.hook_script_ref is not None
# --- end of has_hookscript (...) ---
- def get_hookscript ( self ):
+ def get_hookscript ( self, unsafe=False ):
+ """Returns the HookScript object to which this instance belongs to.
+ Returns None if this UserHookScript is not a link.
+
+ arguments:
+ * unsafe -- do not raise ObjectDisappeared if not linked or hook script
+ disappeared and return None instead.
+
+ Raises: roverlay.util.objects.ObjectDisappeared
+ """
ref = self.hook_script_ref
if ref is False:
return None
+ elif unsafe:
+ return None if ref is None else ref.deref_unsafe()
elif ref is None:
raise roverlay.util.objects.ObjectDisappeared()
else:
@@ -270,10 +317,12 @@ class UserHookScript ( HookScriptBase ):
# --- end of get_hookscript (...) ---
def get_hookscript_path ( self ):
+ """Returns the link target (can be identical to the fspath attribute)."""
return self.hook_script_fspath
# --- end of get_hookscript_path (...) ---
def get_dest_name ( self ):
+ """Returns the link name."""
return self.filename
# --- end of get_dest_name (...) ---
@@ -281,11 +330,20 @@ class UserHookScript ( HookScriptBase ):
class HookScript ( HookScriptBase ):
+ """A hook script that resides in the 'static data' dir."""
def __init__ ( self, fspath, filename=None ):
+ """HookScript constructor.
+ Also looks up static information (hook priority etc.).
+
+ arguments:
+ * fspath -- absolute path to the hook script
+ * filename -- name of the hook script
+ Defaults to os.path.basename(fspath).
+ """
super ( HookScript, self ).__init__ ( fspath, filename=filename )
- static_entry = self.get_static_info()
+ static_entry = roverlay.static.hookinfo.get ( self.name, None )
if static_entry is not None:
self.default_events = static_entry[0]
self.priority = static_entry[1]
@@ -297,50 +355,87 @@ class HookScript ( HookScriptBase ):
# --- end of __init__ (...) ---
def add_user_script ( self, user_script ):
+ """Registers a UserHookScript linking to this object (as reference)."""
self.user_script_refs.add ( user_script.get_ref() )
# --- end of add_user_script (...) ---
- def iter_user_scripts ( self, ignore_missing=True ):
+ def iter_user_scripts ( self, ignore_missing=True, check_backref=True ):
+ """Iterates over all UserHookScripts linked to this object.
+
+ arguments:
+ * ignore_missing -- do not fail if a referenced object disappeared.
+ Defaults to True.
+ * check_backref -- if True: ignore UserHookScripts that do no longer
+ link to this object. Defaults to True.
+ """
if ignore_missing:
+ if check_backref:
+ for ref in self.user_script_refs:
+ obj = ref.deref_unsafe()
+ if (
+ obj is not None and
+ obj.get_hookscript ( unsafe=True ) is self
+ ):
+ yield obj
+ else:
+ for ref in self.user_script_refs:
+ obj = ref.deref_unsafe()
+ if obj is not None:
+ yield obj
+ elif check_backref:
for ref in self.user_script_refs:
- obj = ref.deref_unsafe()
- if obj is not None:
- yield obj
+ obj = obj.deref_safe()
+ if obj.get_hookscript ( unsafe=False ) is self:
+ yield obj.deref_safe()
else:
for ref in self.user_script_refs:
yield obj.deref_safe()
# --- end of iter_user_scripts (...) ---
- def get_hookscript ( self ):
- return self
- # --- end of get_hookscript (...) ---
-
- def get_hookscript_path ( self ):
- return self.fspath
- # --- end of get_hookscript_path (...) ---
-
# --- end of HookScript ---
class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
+ """A directory containing hook scripts."""
HOOK_SCRIPT_CLS = None
DIRNAMES_IGNORE = frozenset({ '.*', })
FILENAMES_IGNORE = frozenset({ '.*', })
def dirname_filter ( self, dirname, _fnmatch=fnmatch.fnmatch ):
+ """Returns True if dirname does not match any pattern in
+ DIRNAMES_IGNORE, else False.
+
+ arguments:
+ * dirname --
+ * _fnmatch -- function for matching dirname against pattern.
+ Defaults to fnmatch.fnmatch.
+ """
return all (
not _fnmatch ( dirname, pat ) for pat in self.DIRNAMES_IGNORE
)
# --- end of dirname_filter (...) ---
def filename_filter ( self, filename, _fnmatch=fnmatch.fnmatch ):
+ """Returns True if dirname does not match any pattern in
+ FILENAMES_IGNORE, else False.
+
+ arguments:
+ * filename --
+ * _fnmatch -- function for matching filename against pattern.
+ Defaults to fnmatch.fnmatch.
+ """
return all (
not _fnmatch ( filename, pat ) for pat in self.FILENAMES_IGNORE
)
# --- end of filename_filter (...) ---
def __init__ ( self, root ):
+ """HookScriptDirBase constructor.
+
+ arguments:
+ * root -- absolute filesystem path to the hook script dir's root dir
+ """
super ( HookScriptDirBase, self ).__init__()
self.root = root
@@ -348,11 +443,18 @@ class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
self.writable = None
# --- end of __init__ (...) ---
- def __bool__ ( self ):
- return bool ( self.scripts )
- # --- end of __bool__ (...) ---
+ def __len__ ( self ):
+ """Returns the number of scripts."""
+ # also used in boolean context
+ return len ( self.scripts )
+ # --- end of __len__ (...) ---
def get_fspath ( self, relpath=None ):
+ """Returns the filesystem path of this dir or of a sub dir/file.
+
+ arguments:
+ * relpath -- sub dir/file path relative to the root. Defaults to None.
+ """
if relpath:
return self.root + os.sep + str ( relpath )
else:
@@ -360,48 +462,100 @@ class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
# --- end of get_fspath (...) ---
def get_script ( self, name ):
+ """Returns the script with the given name.
+ Typically faster than find_by_name(), but less accurate when dealing
+ with user scripts.
+
+ arguments:
+ * name -- script name
+ """
script = self.scripts [name]
- return script if script.is_visible() else None
+ if script.is_visible():
+ return script
+ else:
+ raise KeyError ( name )
# --- end of get_scripts (...) ---
def iter_scripts ( self ):
+ """Generator that yields all visible scripts."""
for script in self.scripts.values():
if script.is_visible():
yield script
# --- end of iter_scripts (...) ---
def find_all ( self, condition, c_args=(), c_kwargs={} ):
+ """Generator that yields all visible scripts for which
+ condition ( script, *c_args, **c_kwargs ) evaluates to True.
+
+ arguments:
+ * condition -- function/callable
+ * c_args -- packed args for condition. Defaults to ().
+ * c_kwargs -- packed keyword args for condition. Defaults to {}.
+ """
for script in self.iter_scripts():
if condition ( script, *c_args, **c_kwargs ):
yield script
# --- end of find_all (...) ---
def find ( self, condition, c_args=(), c_kwargs={}, **kw ):
+ """Like find_all(), but returns the first match, if any, else None.
+
+ arguments:
+ * condition -- function/callable
+ * c_args -- packed args for condition. Defaults to ().
+ * c_kwargs -- packed keyword args for condition. Defaults to {}.
+ * **kw -- additional keyword args for find_all().
+ """
try:
return next ( self.find_all ( condition, c_args, c_kwargs, **kw ) )
except StopIteration:
return None
# --- end of find (...) ---
- def find_by_name ( self, name, **kw ):
- return self.find (
- lambda s, n: s.name == n, c_args=( name, ), **kw
- )
- # --- end of find_all_by_name (...) ---
-
def find_all_by_name ( self, name, **kw ):
+ """Generator that yields all visible scripts whose names matches the
+ given one.
+
+ arguments:
+ * name --
+ * **kw -- additional keyword args for find_all()
+ """
return self.find_all (
lambda s, n: s.name == n, c_args=( name, ), **kw
)
# --- end of find_all_by_name (...) ---
+ def find_by_name ( self, name, **kw ):
+ """Like find_all_by_name(), but returns the first match, if any,
+ else None.
+
+ arguments:
+ * name --
+ * **kw --
+ """
+ try:
+ return next ( self.find_all_by_name ( name, **kw ) )
+ except StopIteration:
+ return None
+ # --- end of find_by_name (...) ---
+
def find_all_by_name_begin ( self, prefix, **kw ):
+ """Generator that yields all visible scripts whose names begin with
+ the given prefix.
+
+ arguments:
+ * prefix --
+ * **kw -- additional keyword args for find_all()
+ """
return self.find_all (
lambda s, pre: s.name.startswith ( pre ), c_args=( prefix, ), **kw
)
# --- end of find_all_by_name_begin (...) ---
def scan ( self ):
+ """Scans the filesystem location of this hook script dir for hook
+ scripts and adds them to the scripts attribute.
+ """
root = self.root
try:
filenames = sorted ( os.listdir ( root ) )
@@ -422,35 +576,97 @@ class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
class NestedHookScriptDirBase ( HookScriptDirBase ):
+ """A hook script dir with a nested structure (hook scripts in subdirs)."""
+
SUBDIR_CLS = collections.OrderedDict
def get_script ( self, name ):
- return [
- script for script in self.iter_scripts() if script.name == name
- ]
- # --- end of get_script (...) ---
+ """Returns a list of all visible scripts with the given name.
- def create_hookscript ( self, fspath, filename, root ):
- return self.HOOK_SCRIPT_CLS ( fspath, filename=filename )
- # --- end of create_hookscript (...) ---
+ arguments:
+ * name --
+ """
+ return list ( self.find_all_by_name ( name ) )
+ # --- end of get_script (...) ---
def scan ( self, prune_empty=True ):
- self.scripts = roverlay.fsutil.get_fs_dict (
- self.root, create_item=self.create_hookscript,
- dict_cls=self.SUBDIR_CLS, dirname_filter=self.dirname_filter,
- filename_filter=self.filename_filter, include_root=False,
- prune_empty=prune_empty,
+ """Scans the hook script dir for hook scripts.
+ Calls scan_scripts() when done.
+
+ arguments:
+ * prune_empty -- whether to keep empty dirs in the scripts dict
+ (False) or not (True). Defaults to True.
+ """
+ def get_script_name ( filename ):
+ """Returns the script name of the given filename.
+
+ arguments:
+ * filename --
+ """
+ prio, sepa, name = filename.partition ( '-' )
+ if name:
+ try:
+ prio_int = int ( prio, 10 )
+ except ValueError:
+ return filename
+ else:
+ return name
+ else:
+ return filename
+ # --- end of get_script_name (...) ---
+
+ def create_hookscript (
+ fspath, filename, root, HOOK_SCRIPT_CLS=self.HOOK_SCRIPT_CLS
+ ):
+ """Creates a new hook script object.
+
+ arguments:
+ * fspath -- absolute path to the script file
+ * filename -- name of the script file
+ * root -- directory of the script file
+ * HOOK_SCRIPT_CLS -- hook script class.
+ Defaults to elf.HOOK_SCRIPT_CLS.
+ """
+ return HOOK_SCRIPT_CLS ( fspath, filename=filename )
+ # --- end of create_hookscript (...) ---
+
+ new_scripts = roverlay.fsutil.get_fs_dict (
+ self.root,
+ create_item = create_hookscript,
+ dict_cls = self.SUBDIR_CLS,
+ dirname_filter = self.dirname_filter,
+ filename_filter = self.filename_filter,
+ include_root = False,
+ prune_empty = prune_empty,
+ file_key = get_script_name,
)
+ self.scripts.update ( new_scripts )
self.scan_scripts()
# --- end of scan (...) ---
def scan_scripts ( self ):
+ """Performs additional actions after scanning scripts, e.g.
+ setting correct event attributes.
+ """
for event, hook in self.iter_scripts():
if hook.event is None:
hook.event = event
# --- end of scan (...) ---
def iter_scripts ( self, event=None, ignore_missing=False ):
+ """Generator that yields all visible script.
+
+ Depending on the event parameter, the items are either
+ 2-tuples(event_name, script) (event is None) or scripts.
+
+ arguments:
+ * event -- specific event to iterator over (or None for all)
+ Defaults to None.
+ * ignore_missing -- do not fail if event subdir is missing.
+ only meaningful if event is not None
+ Defaults to False.
+ """
+
# roverlay uses per-event subdirs containing hook files
SUBDIR_CLS = self.SUBDIR_CLS
@@ -474,6 +690,16 @@ class NestedHookScriptDirBase ( HookScriptDirBase ):
# --- end of iter_scripts (...) ---
def find_all ( self, condition, c_args=(), c_kwargs={}, event=None ):
+ """Generator that yields all scripts matching the given condition.
+ Can optionally be restricted to a single event subdir.
+ See HookScriptDirBase.find_all() for details.
+
+ arguments:
+ * condition --
+ * c_args --
+ * c_kwargs --
+ * event --
+ """
if event is None:
for event_name, script in self.iter_scripts():
if condition ( script, *c_args, **c_kwargs ):
@@ -485,6 +711,11 @@ class NestedHookScriptDirBase ( HookScriptDirBase ):
# --- end of find_all_by_name (...) ---
def get_subdir ( self, event_name ):
+ """Returns the requested event subdir dict (by creating it if necessary)
+
+ arguments:
+ * event_name --
+ """
subdir = self.scripts.get ( event_name, None )
if subdir is None:
subdir = self.SUBDIR_CLS()
@@ -498,10 +729,17 @@ class NestedHookScriptDirBase ( HookScriptDirBase ):
class UserHookScriptDir ( NestedHookScriptDirBase ):
+ """A nested hook script dir that contains UserHookScripts."""
HOOK_SCRIPT_CLS = UserHookScript
def __init__ ( self, *args, **kwargs ):
+ """See HookScriptDirBase.__init__().
+
+ arguments:
+ * *args -- passed to super().__init__()
+ * **kwargs -- passed to super().__init__()
+ """
super ( UserHookScriptDir, self ).__init__ ( *args, **kwargs )
# per-event prio gen
## self._prio_gen = collections.defaultdict (
@@ -511,16 +749,23 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
# --- end of __init__ (...) ---
def _create_new_prio_gen ( self ):
+ """Creates and returns a new priority generator."""
return roverlay.util.counter.SkippingPriorityGenerator (
10, skip=roverlay.static.hookinfo.get_priorities()
)
# --- end of _create_new_prio_gen (...) ---
def _get_prio_gen ( self, event_name ):
+ """Returns a priority generator for the given event.
+
+ arguments:
+ * event_name --
+ """
return self._prio_gen
# --- end of _get_prio_gen (...) ---
def scan_scripts ( self ):
+ """Performs additional actions after scanning the directory."""
prios = collections.defaultdict ( list )
for event, hook in self.iter_scripts():
if hook.event is None:
@@ -536,6 +781,17 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
def create_hookdir_refs ( self,
hook_dir, overwrite=False, compare_fspath=True
):
+ """Establishes links (references) from user scripts to hook scripts
+ in the given hook dir (which usually creates backreferences).
+
+ arguments:
+ * hook_dir -- hook directory (HookScriptDir)
+ * overwrite -- overwrite existing references
+ * compare_fspath -- if True: link only if filesystem paths
+ (link target, script filepath) match
+ else: link if names match
+ Defaults to True.
+ """
for event, user_script in self.iter_scripts():
if overwrite or not user_script.has_hookscript():
try:
@@ -550,6 +806,15 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
# --- end of create_hookdir_refs (...) ---
def make_hookdir_refs ( self, hook_dir, overwrite=False ):
+ """Calls create_hookdir_refs() twice, first with compare_fspath=True,
+ and then with compare_fspath=False, so that exact matches are preferred.
+
+ See create_hookdir_refs() for details.
+
+ arguments:
+ * hook_dir --
+ * overwrite --
+ """
# try exact fs path matches first, then use name-based ones
self.create_hookdir_refs (
hook_dir, overwrite=overwrite, compare_fspath=True
@@ -560,6 +825,11 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
# --- end of make_hookdir_refs (...) ---
def add_entry_unsafe ( self, hook ):
+ """Adds a hook object (UserHookScript) to this script directory.
+
+ arguments:
+ * hook -- hook object (the event attribute has to be set)
+ """
if hook.event:
self.get_subdir ( hook.event ) [hook.name] = hook
else:
@@ -568,6 +838,13 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
# --- end of add_entry_unsafe (...) ---
def get_entry_for_link ( self, hook, event_name ):
+ """Returns a UserHookScript object that can be used to link against
+ the given HookScript object.
+
+ arguments:
+ * hook --
+ * event_name --
+ """
existing_entry = self.find_by_name ( hook.name, event=event_name )
if existing_entry:
return existing_entry
@@ -581,12 +858,6 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
return user_hook
# --- end of get_entry_for_link (...) ---
- def iter_nonlinked ( self ):
- for event, script in self.iter_scripts():
- if not script.has_hookscript():
- yield script
- # --- end of iter_nonlinked (...) ---
-
# --- end of UserHookScriptDir ---
@@ -595,12 +866,24 @@ class HookScriptDir ( HookScriptDirBase ):
HOOK_SCRIPT_CLS = HookScript
def iter_linked ( self ):
- # 2-tuple ( hook_script, list ( linked_user_scripts ) )
+ """Generator that yields
+ 2-tuples ( HookScript, list( UserHookScript references ) ).
+
+ The UserHookScript references list can be empty.
+ """
for script in self.iter_scripts():
yield ( script, list ( script.iter_user_scripts() ) )
# --- end of iter_linked (...) ---
def iter_default_scripts ( self, unpack=False ):
+ """Generator that yields all default scripts.
+
+ Depending on the unpack parameter, the items are either HookScripts
+ (False) or 2-tuples (event, HookScript) (True).
+
+ arguments:
+ * unpack -- defaults to False
+ """
if unpack:
for script in self.iter_scripts():
if script.default_events:
@@ -613,6 +896,9 @@ class HookScriptDir ( HookScriptDirBase ):
# --- end of iter_default_scripts (...) ---
def get_default_scripts ( self ):
+ """
+ Returns a dict containg per-event lists of the default HookScripts.
+ """
return roverlay.util.dictwalk.dictmerge (
self.iter_default_scripts ( unpack=True ),
get_value=lambda kv:kv[1]
@@ -626,12 +912,25 @@ class HookScriptDir ( HookScriptDirBase ):
class SetupHookEnvironment (
roverlay.setupscript.baseenv.SetupSubEnvironment
):
+ """'Environment' for managing hooks."""
NEEDS_CONFIG_TREE = True
def format_hook_info_lines ( self,
info, sort_info=True, append_newline=False
):
+ """Generator that accepts a list of
+ (scripts, list ( event to which script is linked, priority)) and yields
+ formatted text lines "<script name> | <event>(<prio>)..." for each
+ script.
+
+ arguments:
+ * info --
+ * sort_info -- whether to sort info (by "has events",name)
+ Defaults to True.
+ * append_newline -- whether to append a newline at the end
+ Defaults to False.
+ """
max_name_len = min ( 30, max ( len(x[0]) for x in info ) )
event_names = set()
@@ -670,6 +969,14 @@ class SetupHookEnvironment (
# --- end of format_hook_info_lines (...) ---
def get_hook_root_info ( self, nonlinked_only=False ):
+ """Returns a list with information about the hook root suitable
+ for being formatted by format_hook_info_lines().
+
+ arguments:
+ * nonlinked_only -- whether to exclude scripts that are linked to
+ >= 1 event(s) (True) or not (False).
+ Defaults to False.
+ """
if nonlinked_only:
return [
( script.name, [] )
@@ -687,6 +994,9 @@ class SetupHookEnvironment (
# --- end of get_hook_root_info (...) ---
def get_user_hook_info ( self ):
+ """Returns a list with information about the user hook root suitable
+ for being formatted by format_hook_info_lines().
+ """
return [
( s.name, [ ( s.event or "undef", s.priority ) ] )
for event, s in self.user_hooks.iter_scripts()
@@ -694,6 +1004,8 @@ class SetupHookEnvironment (
# --- end of get_user_hook_info (...) ---
def gen_hook_info_lines ( self, append_newline=True ):
+ """Generator that yields (formatted) text lines with information
+ about hooks in the user hook root and the hook root."""
info = (
self.get_user_hook_info()
+ self.get_hook_root_info ( nonlinked_only=True )
@@ -705,7 +1017,7 @@ class SetupHookEnvironment (
# --- end of gen_hook_info_lines (...) ---
def setup ( self ):
-
+ """Performs subclass-specific initialization."""
self.hook_overwrite_control = self.setup_env.hook_overwrite
additions_dir = self.config.get ( 'OVERLAY.additions_dir', None )
@@ -732,6 +1044,15 @@ class SetupHookEnvironment (
# --- end of setup (...) ---
def check_link_allowed ( self, source, link, link_name ):
+ """Returns whether symlinking link->source is allowed.
+ This decision is made based on the fileystem "state" of the link
+ and the HookOverwriteControl object (bound to this instance).
+
+ arguments:
+ * source -- link destination (absolute filesystem path)
+ * link -- link file (absolute filesystem path)
+ * link_name -- file name of the link
+ """
if os.path.lexists ( link ):
allow_overwrite = False
@@ -780,6 +1101,14 @@ class SetupHookEnvironment (
# --- end of check_link_allowed (...) ---
def link_hooks_v ( self, event_name, hooks ):
+ """Links several hooks to the given event.
+
+ Returns True on success, else False.
+
+ arguments:
+ * event_name --
+ * hooks --
+ """
success = False
user_hooks = self.user_hooks
@@ -830,6 +1159,14 @@ class SetupHookEnvironment (
# --- end of link_hooks_v (...) ---
def link_hooks_to_events ( self, hooks, events ):
+ """Links several hooks to several events.
+
+ Returns True on success, else False.
+
+ arguments:
+ * hooks --
+ * events --
+ """
success = True
for event_name in events:
if not self.link_hooks_v ( event_name, hooks ):
@@ -838,6 +1175,15 @@ class SetupHookEnvironment (
# --- end of link_hooks_to_events (...) ---
def unlink_hooks ( self, hooks, symlinks_only=True ):
+ """Removes several hooks.
+
+ Returns: None (implicit)
+
+ arguments:
+ * hooks -- iterable of UserHookScripts
+ * symlinks_only -- if True: remove symlinks only, else remove files
+ else well. Defaults to True.
+ """
unlink = self.setup_env.fs_private.unlink
if not symlinks_only:
@@ -861,6 +1207,7 @@ class SetupHookEnvironment (
# --- end of unlink_hooks (...) ---
def enable_defaults ( self ):
+ """Enables all default hooks."""
# not strict: missing hooks are ignored
success = False
if self.hook_root:
@@ -875,6 +1222,10 @@ class SetupHookEnvironment (
# --- end of enable_defaults (...) ---
def run ( self ):
+ """main() function that gets its information from the setup env.
+
+ Supports show and add/del <hook> <event>...
+ """
setup_env = self.setup_env
options = setup_env.options
command = options ['hook.action']
@@ -883,6 +1234,7 @@ class SetupHookEnvironment (
if command in { 'show', }:
self.info ( '\n'.join ( self.gen_hook_info_lines() ) )
+ # -- end <show>
elif command in { 'add', }:
hooks = list ( self.hook_root.find_all_by_name_begin ( hook_name ) )
@@ -892,11 +1244,17 @@ class SetupHookEnvironment (
)
# FIXME: exit code?
+ elif "all" in hooks:
+ self.error (
+ "cannot add hooks to the (virtual) \'all\' event!\n"
+ )
+
elif len ( hooks ) == 1:
- # good
+ # exactly one hook matches
self.link_hooks_to_events ( hooks, hook_events )
else:
+ # > 1 matches, find exact matches
exact_matches = [ k for k in hooks if k.name == hook_name ]
if not exact_matches or len ( exact_matches ) != 1:
@@ -908,6 +1266,8 @@ class SetupHookEnvironment (
else:
self.link_hooks_to_events ( exact_matches, hook_events )
+ # -- end <add>
+
elif command in { 'del', }:
hooks_to_unlink = []
@@ -978,6 +1338,8 @@ class SetupHookEnvironment (
# -- end if
self.unlink_hooks ( hooks_to_unlink )
+ # -- end <del>
+
else:
raise NotImplementedError ( command )
# --- end of run (...) ---
next reply other threads:[~2013-09-19 15:00 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-19 15:00 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2014-04-01 16:38 [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/ André Erdmann
2014-02-22 14:56 André Erdmann
2014-02-21 17:36 André Erdmann
2014-02-17 17:22 André Erdmann
2014-02-17 17:10 André Erdmann
2013-09-18 15:24 André Erdmann
2013-09-13 15:20 André Erdmann
2013-09-13 15:10 André Erdmann
2013-09-13 15:10 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-11 14:50 André Erdmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1379602803.daefc87c578f6b8a4b7bd903c40a1d84adbead37.dywi@gentoo \
--to=dywi@mailerd.de \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox