public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-19 15:00 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-19 15:00 UTC (permalink / raw
  To: gentoo-commits

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 (...) ---


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2014-04-01 16:38 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2014-04-01 16:38 UTC (permalink / raw
  To: gentoo-commits

commit:     9402ffb0190bed041670f725d477603c247febad
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Mar 31 17:15:00 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Apr  1 16:36:30 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9402ffb0

setupscript, arg parser: add ROVERLAY_TARGET_TYPE

... to epilog

---
 roverlay/setupscript/runtime.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index afe9daa..b9b7ed0 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -426,8 +426,10 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
          defaults    = self.get_parser_defaults(),
          epilog      = (
             'Environment variables:\n'
-            '* ROVERLAY_PRJROOT   - path to roverlay\'s source dir\n'
-            '* ROVERLAY_INSTALLED - mark roverlay as installed (if set and not empty)\n'
+            '* ROVERLAY_PRJROOT     - path to roverlay\'s source dir\n'
+            '* ROVERLAY_INSTALLED   - mark roverlay as installed\n'
+            '                          (if set and not \'0\', \'no\', \'n\' \'false\')\n'
+            '* ROVERLAY_TARGET_TYPE - set target environment type\n'
          )
       )
    # --- end of create_argparser (...) ---


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2014-02-22 14:56 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2014-02-22 14:56 UTC (permalink / raw
  To: gentoo-commits

commit:     1a8328b48d7918107cffa391096ec0cdfa8d9212
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Feb 21 18:32:11 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Feb 21 18:32:11 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1a8328b4

roverlay/setupscript/runtime: minor cleanup

---
 roverlay/setupscript/runtime.py | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 0f4294d..2afbc9f 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -330,21 +330,27 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
    def __init__ ( self, *args, **kwargs ):
       super ( SetupEnvironment, self ).__init__ ( *args, **kwargs )
 
-      self.UID             = os.getuid()
-      self.GID             = os.getgid()
+      self.UID                = os.getuid()
+      self.GID                = os.getgid()
 
-      self.expanduser      = None
-      self.fs_ops          = None
-      self.fs_ops_virtual  = None
+      # filesystem-related functions
+      self.expanduser         = None
+      self.fs_private_virtual = None
+      self.fs_private         = None
+      self.fs_shared_virtual  = None
+      self.fs_shared          = None
+
+      self.want_chown         = None
+      self.data_root          = None
+      self.work_root          = None
+      self.conf_root          = None
+      self.user_conf_root     = None
+      self.additions_dir      = None
+      self.hook_overwrite     = None
 
-      self.want_chown      = None
-      self.data_root       = None
-      self.work_root       = None
-      self.conf_root       = None
-      self.user_conf_root  = None
 
 # not used
-#      COLUMNS = os.environ.get ( 'COLUMNS', 78 )
+#      COLUMNS = os.environ.get ( 'COLUMNS', 78 ) # should use termios/...
 #
 #      self.text_wrapper = textwrap.TextWrapper (
 #         width=COLUMNS, initial_indent='', subsequent_indent='',


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2014-02-21 17:36 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2014-02-21 17:36 UTC (permalink / raw
  To: gentoo-commits

commit:     796c1d77dafadccc44e028d91366228502af4416
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Feb 20 21:20:28 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Feb 20 21:20:28 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=796c1d77

roverlay-setup, config import: minor improvement

fs_ops.unlink() always succeeds in --pretend mode (no-op), so "roverlay-setup
--pretend" gives misleading output when user_config_root==config_root.

=> do not reset user_conf_root in --pretend mode if it isn't a symlink.

---
 roverlay/setupscript/initenv.py | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/roverlay/setupscript/initenv.py b/roverlay/setupscript/initenv.py
index 58677e1..ef06436 100644
--- a/roverlay/setupscript/initenv.py
+++ b/roverlay/setupscript/initenv.py
@@ -186,15 +186,11 @@ class SetupInitEnvironment (
       # assert os.path.isdir ( os.path.dirname(user_conf_root) == work_root )
 
       if user_conf_root is None and (
-         fs_ops.unlink ( setup_env.user_conf_root )
+         not pretend or os.path.islink ( setup_env.user_conf_root )
       ):
-         # config_root was a symlink
-
-         if pretend:
-            user_conf_root = setup_env.user_conf_root
-         else:
+         if fs_ops.unlink ( setup_env.user_conf_root ):
+            # user_conf_root was a symlink
             user_conf_root = setup_env.get_user_config_root()
-
       # -- end if
 
 


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2014-02-17 17:22 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2014-02-17 17:22 UTC (permalink / raw
  To: gentoo-commits

commit:     5af9d454a5da4eac702857ea392e6725e6cdd013
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Feb 17 17:21:48 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Feb 17 17:21:48 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5af9d454

roverlay-setup, init: fix config file location (#2)

+ handle standalone versions of roverlay

---
 roverlay/setupscript/runtime.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 5aab1d8..0f4294d 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -406,10 +406,11 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
    # --- end of get_user_config_root (...) ---
 
    def get_config_file_path ( self ):
-      return (
-         self._get_config_roots()[1]
-         + os.sep + self.access_constant ( 'config_file_name' )
-      )
+      cname = self.access_constant ( 'config_file_name' )
+      if self.is_installed():
+         return self._get_config_roots()[1] + os.sep + cname
+      else:
+         return self.prjroot + os.sep + cname
    # --- end of get_config_file_path (...) ---
 
    def create_new_target_config ( self ):


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2014-02-17 17:10 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2014-02-17 17:10 UTC (permalink / raw
  To: gentoo-commits

commit:     a6bc40c39930cbaf419e7440a6d478954d49fd16
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Feb 17 17:09:38 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Feb 17 17:09:38 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a6bc40c3

roverlay-setup, init: fix config file location

Write R-overlay.conf to user_conf_root (or conf_root), not work_root.

---
 roverlay/setupscript/runtime.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 56b2a8b..5aab1d8 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -407,7 +407,8 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
 
    def get_config_file_path ( self ):
       return (
-         self.work_root + os.sep + self.access_constant ( 'config_file_name' )
+         self._get_config_roots()[1]
+         + os.sep + self.access_constant ( 'config_file_name' )
       )
    # --- end of get_config_file_path (...) ---
 


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-18 15:24 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-18 15:24 UTC (permalink / raw
  To: gentoo-commits

commit:     a9cde023d35bad3c87fc677d5bff862248426646
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Sep 18 15:23:25 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Sep 18 15:23:25 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a9cde023

roverlay-setup: proper priority assignment (EXP)

Set priority on a per-user-dir basis.
"experimental": needs a fixup/cleanup

---
 roverlay/setupscript/hookenv.py | 227 +++++++++++++++++++++++++---------------
 1 file changed, 143 insertions(+), 84 deletions(-)

diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index 8d70f02..d361801 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -147,6 +147,17 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
       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 (...) ---
@@ -167,9 +178,20 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
       pass
    # --- end of get_hookscript_path (...) ---
 
-   @roverlay.util.objects.abstractmethod
-   def get_dest_name ( self, *args, **kwargs ):
-      pass
+   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 ---
@@ -177,9 +199,36 @@ class HookScriptBase ( roverlay.util.objects.Referenceable ):
 
 class UserHookScript ( HookScriptBase ):
 
-   def __init__ ( self, fspath, filename=None, event=None ):
+   @classmethod
+   def create_for_hook (
+      cls, hook, destdir, event_name, priority_gen,
+      file_ext='.sh', digit_len=2
+   ):
+      if type ( priority_gen ) == int:
+         prio = priority_gen
+      elif hook.has_priority():
+         prio = hook.priority
+      else:
+         prio = next ( priority_gen )
+
+      filename = "{prio:0>{dlen}}-{name}{fext}".format (
+         prio = prio,
+         dlen = digit_len,
+         name = hook.name,
+         fext = file_ext,
+      )
+
+      instance = cls (
+         ( destdir + os.sep + filename ), filename=filename,
+         event=event_name, priority=prio,
+      )
+      instance.set_hookscript ( hook )
+      return instance
+   # --- end of create_for_hook (...) ---
+
+   def __init__ ( self, fspath, filename=None, event=None, priority=True ):
       super ( UserHookScript, self ).__init__ (
-         fspath, filename=filename, priority=True
+         fspath, filename=filename, priority=priority
       )
 
       self.hook_script_fspath = os.path.realpath ( self.fspath )
@@ -190,7 +239,6 @@ class UserHookScript ( HookScriptBase ):
       else:
          self.hook_script_ref = False
 
-
       self.event = event
    # --- end of __init__ (...) ---
 
@@ -250,8 +298,6 @@ class HookScript ( HookScriptBase ):
 
    def add_user_script ( self, user_script ):
       self.user_script_refs.add ( user_script.get_ref() )
-      if self.priority is None and user_script.has_priority():
-         self.priority = user_script.priority
    # --- end of add_user_script (...) ---
 
    def iter_user_scripts ( self, ignore_missing=True ):
@@ -265,30 +311,6 @@ class HookScript ( HookScriptBase ):
             yield obj.deref_safe()
    # --- end of iter_user_scripts (...) ---
 
-   def set_priority_from_generator ( self, number_gen, only_if_unset=True ):
-      if self.priority is None:
-         self.priority = next ( number_gen )
-         return True
-      elif only_if_unset or self.priority < 0:
-         return False
-      else:
-         self.priority = next ( number_gen )
-         return True
-   # --- end of set_priority_from_generator (...) ---
-
-   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 None or 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,
-      )
-   # --- end of get_dest_name (...) ---
-
    def get_hookscript ( self ):
       return self
    # --- end of get_hookscript (...) ---
@@ -361,11 +383,17 @@ class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
          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 ):
       return self.find_all (
          lambda s, n: s.name == n, c_args=( name, ), **kw
       )
-   # --- end of find_by_name (...) ---
+   # --- end of find_all_by_name (...) ---
 
    def find_all_by_name_begin ( self, prefix, **kw ):
       return self.find_all (
@@ -413,7 +441,10 @@ class NestedHookScriptDirBase ( HookScriptDirBase ):
          filename_filter=self.filename_filter, include_root=False,
          prune_empty=prune_empty,
       )
+      self.scan_scripts()
+   # --- end of scan (...) ---
 
+   def scan_scripts ( self ):
       for event, hook in self.iter_scripts():
          if hook.event is None:
             hook.event = event
@@ -453,6 +484,16 @@ class NestedHookScriptDirBase ( HookScriptDirBase ):
                yield script
    # --- end of find_all_by_name (...) ---
 
+   def get_subdir ( self, event_name ):
+      subdir = self.scripts.get ( event_name, None )
+      if subdir is None:
+         subdir = self.SUBDIR_CLS()
+         self.scripts [event_name] = subdir
+      # -- end if
+      return subdir
+   # --- end of get_subdir (...) ---
+
+
 # --- end of NestedHookScriptDirBase ---
 
 
@@ -460,6 +501,38 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
 
    HOOK_SCRIPT_CLS = UserHookScript
 
+   def __init__ ( self, *args, **kwargs ):
+      super ( UserHookScriptDir, self ).__init__ ( *args, **kwargs )
+      # per-event prio gen
+##      self._prio_gen = collections.defaultdict (
+##         self._create_new_prio_gen,
+##      )
+      self._prio_gen = self._create_new_prio_gen()
+   # --- end of __init__ (...) ---
+
+   def _create_new_prio_gen ( self ):
+      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 ):
+      return self._prio_gen
+   # --- end of _get_prio_gen (...) ---
+
+   def scan_scripts ( self ):
+      prios = collections.defaultdict ( list )
+      for event, hook in self.iter_scripts():
+         if hook.event is None:
+            hook.event = event
+         if hook.has_priority():
+            prios [event].append ( hook.priority )
+      # -- end for
+
+      for event, priolist in prios.items():
+         self._get_prio_gen ( event ).add_generated ( priolist )
+   # --- end of scan (...) ---
+
    def create_hookdir_refs ( self,
       hook_dir, overwrite=False, compare_fspath=True
    ):
@@ -486,27 +559,27 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
       )
    # --- end of make_hookdir_refs (...) ---
 
-   def register_hook_link_unsafe ( self, event_name, hook, link, link_name ):
-      subdir = self.scripts.get ( event_name, None )
-      if subdir is None or link_name not in subdir:
-         if subdir is None:
-            subdir = self.SUBDIR_CLS()
-            self.scripts [event_name] = subdir
-         # -- end if
-
-         entry = self.HOOK_SCRIPT_CLS ( link, filename=link_name )
-         subdir [link_name] = entry
+   def add_entry_unsafe ( self, hook ):
+      if hook.event:
+         self.get_subdir ( hook.event ) [hook.name] = hook
       else:
-         entry = subdir [link_name]
-      # -- end if
-
-      entry.set_hookscript ( hook, strict=False )
-      if entry.event is None:
-         entry.event = event_name
-      elif entry.event != event_name:
-         raise AssertionError ( "entry.event != event_name" )
+         raise AssertionError ( "hook.event is not set." )
       return True
-   # --- end of register_hook_link_unsafe (...) ---
+   # --- end of add_entry_unsafe (...) ---
+
+   def get_entry_for_link ( self, hook, event_name ):
+      existing_entry = self.find_by_name ( hook.name, event=event_name )
+      if existing_entry:
+         return existing_entry
+      else:
+         user_hook = UserHookScript.create_for_hook (
+            hook         = hook,
+            destdir      = ( self.root + os.sep + event_name ),
+            event_name   = event_name,
+            priority_gen = self._get_prio_gen ( event_name )
+         )
+         return user_hook
+   # --- end of get_entry_for_link (...) ---
 
    def iter_nonlinked ( self ):
       for event, script in self.iter_scripts():
@@ -642,21 +715,6 @@ class SetupHookEnvironment (
       )
       self.hook_root.scan()
 
-      # TODO:
-      #  prio_gen should be bound to user hook dirs (per event dir)
-      #  (priority assignment needs to be changed to realize that)
-      #
-      self._prio_gen = roverlay.util.counter.SkippingPriorityGenerator (
-         30, skip=(
-            h.priority for h in self.hook_root.iter_scripts()
-               if h.has_priority()
-         )
-      )
-      # not strictly necessary
-      self._prio_gen.add_generated (
-         roverlay.static.hookinfo.get_priorities()
-      )
-
       if additions_dir:
          self.user_hooks = UserHookScriptDir (
             os.path.join ( additions_dir, 'hooks' )
@@ -669,11 +727,6 @@ class SetupHookEnvironment (
          self.user_hooks.scan()
          if self.hook_root:
             self.user_hooks.make_hookdir_refs ( self.hook_root )
-
-            self._prio_gen.add_generated (
-               h.priority for ev, h in self.user_hooks.iter_scripts()
-                  if h.has_priority()
-            )
       else:
          self.user_hooks = None
    # --- end of setup (...) ---
@@ -729,40 +782,46 @@ class SetupHookEnvironment (
    def link_hooks_v ( self, event_name, hooks ):
       success = False
 
-      if self.user_hooks is not None and self.user_hooks.writable:
+      user_hooks = self.user_hooks
 
-         destdir = self.user_hooks.get_fspath ( event_name )
-         self.setup_env.fs_private.dodir ( destdir )
+      if user_hooks is not None and user_hooks.writable:
+
+         self.setup_env.fs_private.dodir (
+            user_hooks.get_fspath ( event_name )
+         )
 
          # note that there is a race condition when users manipulate their
          # hook dir while running roverlay-setup
          to_link = []
          for script in hooks:
-            script.set_priority_from_generator ( self._prio_gen )
-            dest_name = script.get_dest_name()
-            link = destdir + os.sep + dest_name
+            user_script = user_hooks.get_entry_for_link ( script, event_name )
 
-            if self.check_link_allowed ( script.fspath, link, dest_name ):
-               to_link.append ( ( script, dest_name, link ) )
+            if self.check_link_allowed (
+               script.fspath, user_script.fspath, user_script.get_dest_name()
+            ):
+               to_link.append ( ( script, user_script ) )
          # -- end for
 
-         register_link  = self.user_hooks.register_hook_link_unsafe
+         register_link  = user_hooks.add_entry_unsafe
          symlink        = self.setup_env.fs_private.symlink
          unlink         = self.setup_env.fs_private.unlink
          relative_links = self.setup_env.options ['hook_relpath']
          success        = True
 
-         for script, dest_name, link in to_link:
+         for script, user_script in to_link:
+            link = user_script.fspath
             unlink ( link )
             if relative_links:
                have_link = symlink (
-                  os.path.relpath ( script.fspath, destdir ), link
+                  os.path.relpath (
+                     script.fspath, os.path.dirname ( link )
+                  ), link
                )
             else:
                have_link = symlink ( script.fspath, link )
 
             if have_link:
-               register_link ( event_name, script, link, dest_name )
+               register_link ( user_script )
             elif have_link is not None:
                success = False
       # -- end if


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-13 15:20 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-13 15:20 UTC (permalink / raw
  To: gentoo-commits

commit:     60a9c209e4c43ec6de3437c3c26ed036b7976f56
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 13 15:19:29 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 13 15:19:29 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=60a9c209

setupscript: --[no-]relpath-hooks

Controls whether links with absolute/relative paths are created.
Defaults to absolute if installed and relative if not.

---
 roverlay/setupscript/hookenv.py | 15 +++++++++++----
 roverlay/setupscript/runtime.py | 13 +++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index 5ffcbdd..001e9cd 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -674,12 +674,19 @@ class SetupHookEnvironment (
                to_link.append ( ( script, dest_name, link ) )
          # -- end for
 
-         register_link = self.user_hooks.register_hook_link_unsafe
-         symlink       = self.setup_env.private_file.symlink
-         success       = True
+         register_link  = self.user_hooks.register_hook_link_unsafe
+         symlink        = self.setup_env.private_file.symlink
+         relative_links = self.setup_env.options ['hook_relpath']
+         success        = True
 
          for script, dest_name, link in to_link:
-            have_link = symlink ( script.fspath, link )
+            if relative_links:
+               have_link = symlink (
+                  os.path.relpath ( script.fspath, destdir ), link
+               )
+            else:
+               have_link = symlink ( script.fspath, link )
+
             if have_link:
                register_link ( event_name, script, link, dest_name )
             elif have_link is not None:

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 43733a3..6ce804b 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -243,6 +243,17 @@ class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
          ),
       )
 
+      arg (
+         '--relpath-hooks', dest='hook_relpath',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help='create hook links with relative paths',
+      )
+      arg (
+         '--no-relpath-hooks', dest='hook_relpath',
+         flags=self.ARG_SHARED_INVERSE|self.ARG_OPT_OUT,
+         help='create hook links with absolute paths',
+      )
+
       return arg
    # --- end of setup_hooks (...) ---
 
@@ -293,6 +304,7 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
             'private_conf_root' : instinfo ['workroot'] + os.sep + 'config',
             'import_config'     : 'symlink=root',
             'additions_dir'     : instinfo ['workroot'] + os.sep + 'files',
+            'hook_relpath'      : False,
          }
       else:
          assert self.prjroot
@@ -304,6 +316,7 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
             'private_conf_root' : prjroot + 'config',
             'import_config'     : 'disable',
             'additions_dir'     : prjroot + 'files',
+            'hook_relpath'      : True,
          }
    # --- end of get_parser_defaults (...) ---
 


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-13 15:10 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-13 15:10 UTC (permalink / raw
  To: gentoo-commits

commit:     0a3962d2d7d9f9ede5316058ec9709c825223e26
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 13 15:03:47 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 13 15:03:47 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0a3962d2

setupscript: support standalone roverlay

This commit adds support for using roverlay-setup with not-installed versions of
roverlay.

For roverlay/setupscript/, this mostly affects the arg parser's defaults, and
allows to make paths in the config file relative to the git repo (IFF a subdir).
Additionally, --import-config gets disabled if roverlay is not installed.

---
 roverlay/setupscript/initenv.py | 21 ++++++++++-
 roverlay/setupscript/runtime.py | 81 +++++++++++++++++++++++++++++++++--------
 2 files changed, 84 insertions(+), 18 deletions(-)

diff --git a/roverlay/setupscript/initenv.py b/roverlay/setupscript/initenv.py
index 5e511f8..2807841 100644
--- a/roverlay/setupscript/initenv.py
+++ b/roverlay/setupscript/initenv.py
@@ -90,15 +90,24 @@ class SetupInitEnvironment (
       yield ( "user\'s config root",
          get_path_option ( 'private_conf_root', self.setup_env.user_conf_root )
       )
+      yield ( "additions dir",
+         get_path_option ( 'additions_dir', self.setup_env.additions_dir )
+      )
 
       import_config = get_option ( 'import_config' )
       if import_config == 'disable':
          yield ( "import config", "no" )
-      else:
+      elif self.setup_env.is_installed():
          yield ( "import config",
             "yes, "
             + self.IMPORT_CONFIG_DESC [import_config].format ( **fmt_vars )
          )
+      else:
+         yield (
+            "import config",
+            'no, standalone roverlay cannot import config '
+            'with mode={!r}'.format ( import_config )
+         )
 
       yield ( "enable default hooks", get_option ( 'want_default_hooks' ) )
 
@@ -147,7 +156,15 @@ class SetupInitEnvironment (
 
    def do_import_config ( self, pretend ):
       """Imports the config."""
-      mode           = self.setup_env.options ['import_config']
+      mode = self.setup_env.options ['import_config']
+
+      if mode == 'disable':
+         self.info ( "config import: disabled.\n" )
+         return
+      elif not self.setup_env.is_installed():
+         self.error ( "config import: disabled due to standalone mode.\n" )
+         return
+
       fs_ops         = self.setup_env.private_dir
       user_conf_root = self.setup_env.get_user_config_root()
       # assert os.path.isdir ( os.path.dirname(user_conf_root) == work_root )

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 5a55515..43733a3 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -129,6 +129,15 @@ class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
          help="additional variables",
       )
 
+      arg (
+         '--prjroot-relpath', dest='prjroot_relpath',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help=(
+            'make --{work,data,conf}-root, --{conf,additions}-dir '
+            'relative to ROVERLAY_PRJROOT (for distributing config files)'
+         )
+      )
+
       return arg
    # --- end of setup_config (...) ---
 
@@ -141,9 +150,9 @@ class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
                '\'--variable ADDITIONS_DIR={0}\'.'.format ( val )
             )
 
-      self.parsed ['config_vars'].append (
-         "ADDITIONS_DIR=" + self.parsed ['additions_dir']
-      )
+##      self.parsed ['config_vars'].append (
+##         "ADDITIONS_DIR=" + self.parsed ['additions_dir']
+##      )
    # --- end of parse_config (...) ---
 
    def setup_init ( self ):
@@ -274,19 +283,39 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
 #      )
    # --- end of __init__ (...) ---
 
-   def create_argparser ( self ):
-      instinfo = self.access_constant ( 'INSTALLINFO' )
-
-      return SetupArgParser (
-         description = 'roverlay setup script',
-         defaults    = {
+   def get_parser_defaults ( self ):
+      if self.is_installed():
+         instinfo = self.INSTALLINFO
+         return {
             'work_root'         : instinfo ['workroot'],
             'data_root'         : instinfo ['libexec'],
             'conf_root'         : instinfo ['confroot'],
             'private_conf_root' : instinfo ['workroot'] + os.sep + 'config',
             'import_config'     : 'symlink=root',
             'additions_dir'     : instinfo ['workroot'] + os.sep + 'files',
-         },
+         }
+      else:
+         assert self.prjroot
+         prjroot = self.prjroot + os.sep
+         return {
+            'work_root'         : prjroot + 'workdir',
+            'data_root'         : prjroot + 'files',
+            'conf_root'         : prjroot + 'config',
+            'private_conf_root' : prjroot + 'config',
+            'import_config'     : 'disable',
+            'additions_dir'     : prjroot + 'files',
+         }
+   # --- end of get_parser_defaults (...) ---
+
+   def create_argparser ( self ):
+      return SetupArgParser (
+         description = 'roverlay setup script',
+         defaults    = self.get_parser_defaults(),
+         epilog      = (
+            'Environment variables:\n'
+            '* ROVERLAY_PRJROOT   - path to roverlay\'s source dir\n'
+            '* ROVERLAY_INSTALLED - mark roverlay as installed (if set and not empty)\n'
+         )
       )
    # --- end of create_argparser (...) ---
 
@@ -324,24 +353,44 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
    # --- end of _expanduser_pwd (...) ---
 
    def create_config_file ( self, expand_user=False ):
+      def _get_prjroot_relpath ( fspath ):
+         p = os.path.relpath ( fspath, self.prjroot )
+         if p and ( p[0] != '.' or p == '.' ):
+            return p
+         else:
+            return fspath
+      # --- end of get_prjroot_relpath (...) ---
+
+      get_prjroot_relpath = (
+         _get_prjroot_relpath
+            if ( self.options ['prjroot_relpath'] and self.prjroot )
+         else (lambda p: p)
+      )
+
       conf_creator = roverlay.config.defconfig.RoverlayConfigCreation (
-         is_installed = self.is_installed(),
-         work_root    = (
+         is_installed  = self.is_installed(),
+         work_root     = get_prjroot_relpath (
             self.work_root if expand_user else self.options ['work_root']
          ),
-         data_root    = (
+         data_root     = get_prjroot_relpath (
             self.data_root if expand_user else self.options ['data_root']
          ),
-         conf_root    = (
+         conf_root     = get_prjroot_relpath (
             self.user_conf_root if expand_user
             else self.options ['private_conf_root']
          ),
+         additions_dir = get_prjroot_relpath (
+            self.additions_dir if expand_user
+            else self.options ['additions_dir']
+         )
       )
 
       for kv in self.options ['config_vars']:
          key, sepa, value = kv.partition ( '=' )
          if not sepa:
             raise Exception ( "bad variable given: {!r}".format ( kv ) )
+         elif key in { 'ADDITIONS_DIR', 'OVERLAY_ADDITIONS_DIR', }:
+            conf_creator.set_option ( key, get_prjroot_relpath ( value ) )
          else:
             conf_creator.set_option ( key, value )
 
@@ -367,8 +416,7 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
    # --- end of auto_reconfigure (...) ---
 
    def setup ( self ):
-      self.PWD_INITIAL = os.getcwd()
-      self.setup_common()
+      self.setup_common ( allow_prjroot_missing=False )
 
       # ref
       options = self.options
@@ -389,6 +437,7 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
       self.data_root      = expanduser ( options ['data_root'] )
       self.conf_root      = expanduser ( options ['conf_root'] )
       self.user_conf_root = expanduser ( options ['private_conf_root'] )
+      self.additions_dir  = expanduser ( options ['additions_dir'] )
       self.hook_overwrite = (
          roverlay.setupscript.hookenv.HookOverwriteControl.from_str (
             options ['hook_overwrite']


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-13 15:10 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-13 15:10 UTC (permalink / raw
  To: gentoo-commits

commit:     0a59f1f7b3e34459257d018ca252751a35f66cc2
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 13 15:02:47 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 13 15:02:47 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0a59f1f7

setupscript/hookenv, --pretend: handle missing files

+ fix HOOKDIR_SCRIPT_CLS typo

---
 roverlay/setupscript/hookenv.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index ebfe0d1..5ffcbdd 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -7,7 +7,6 @@
 import collections
 import errno
 import fnmatch
-import itertools
 import os
 
 
@@ -180,9 +179,13 @@ class UserHookScript ( HookScriptBase ):
       )
 
       self.hook_script_fspath = os.path.realpath ( self.fspath )
-      self.hook_script_ref    = (
-         False if not os.path.islink ( self.fspath ) else None
-      )
+      if (
+         os.path.islink ( self.fspath ) or not os.path.lexists ( self.fspath )
+      ):
+         self.hook_script_ref = None
+      else:
+         self.hook_script_ref = False
+
 
       self.event = event
    # --- end of __init__ (...) ---
@@ -436,7 +439,7 @@ class UserHookScriptDir ( NestedHookScriptDirBase ):
             self.scripts [event_name] = subdir
          # -- end if
 
-         entry = self.HOOKDIR_CLS ( link, filename=link_name )
+         entry = self.HOOK_SCRIPT_CLS ( link, filename=link_name )
          subdir [link_name] = entry
       else:
          entry = subdir [link_name]


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-12 16:36 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-12 16:36 UTC (permalink / raw
  To: gentoo-commits

commit:     1eb711c0e3f609ef0d0845921f9086dc39da2f5c
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 12 16:33:30 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 12 16:33:30 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1eb711c0

roverlay/setupscript: "hooks" command

Added a "hooks" command for managing hooks. Currently, it is able to print
information about hooks enabled/available. The underlying code (HookScript*,
UserHookScript* classes) supports more, e.g. linking hooks.

Also added a "--overwrite-hooks [<when>]" option to roverlay-setup, which can be
used to control which hooks will be overwritten, e.g. when running the init
command.

---
 roverlay/setupscript/hookenv.py | 641 ++++++++++++++++++++++++++++++++++------
 roverlay/setupscript/initenv.py |   3 +
 roverlay/setupscript/runtime.py |  38 ++-
 3 files changed, 595 insertions(+), 87 deletions(-)

diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index e07b4e7..ebfe0d1 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -6,40 +6,130 @@
 
 import collections
 import errno
+import fnmatch
+import itertools
 import os
 
 
+import roverlay.fsutil
 import roverlay.static.hookinfo
 import roverlay.util.counter
+import roverlay.util.dictwalk
+import roverlay.util.objects
+import roverlay.setupscript.baseenv
+
+
+class HookOverwriteControl ( object ):
+   OV_NONE      = 0
+   OV_SYM_DEAD  = 2**0
+   OV_SYM_EXIST = 2**1
+   OV_SYM       = OV_SYM_DEAD|OV_SYM_EXIST
+   OV_FILE      = 2**2
+   OV_ALL       = ( 2**3 ) - 1
+
+   OV_KEYWORDS = {
+      'none'  : OV_NONE,
+      'dead'  : OV_SYM_DEAD,
+      'links' : OV_SYM,
+      'all'   : OV_ALL,
+   }
+
+   @classmethod
+   def from_str ( cls, vstr ):
+      return cls ( cls.OV_KEYWORDS[vstr] )
+   # --- end of from_str (...) ---
+
+   def __init__ ( self, value ):
+      super ( HookOverwriteControl, self ).__init__()
+      assert isinstance ( value, int ) and value >= 0
+      self.value = value
+   # --- end of __init__ (...) ---
 
+   def can_overwrite ( self, mask=None ):
+      if mask is None:
+         return self.value == self.OV_NONE
+      else:
+         return self.value & mask
+   # --- end of can_overwrite (...) ---
 
-class HookScript ( object ):
+   def overwrite_dead_symlinks ( self ):
+      return self.value & self.OV_SYM_DEAD
+
+   def overwrite_symlinks ( self ):
+      return self.value & self.OV_SYM
+
+   def overwrite_all ( self ):
+      return self.value == self.OV_ALL
+
+   def get_str ( self ):
+      value = self.value
+      def gen_words():
+         if value == self.OV_NONE:
+            yield "none"
+         else:
+            if value & self.OV_SYM_EXIST:
+               if value & self.OV_SYM_DEAD:
+                  yield "symlinks"
+               else:
+                  yield "symlinks to existing files"
+            elif value & self.OV_SYM_DEAD:
+               yield "broken symlinks"
+
+            if value & self.OV_FILE:
+               yield "files"
+      # --- end of gen_words (...) ---
+
+      return ', '.join ( gen_words() ) + " (0x{:x})".format ( value )
+   # --- end of get_str (...) ---
+
+   __str__ = get_str
+
+# --- end of HookOverwriteControl ---
+
+
+class HookScriptBase ( roverlay.util.objects.Referenceable ):
+
+   CACHE_REF = True
+
+   def __init__ ( self,
+      fspath, filename=None, priority=None, is_hidden=False
+   ):
+      """HookScriptBase constructor.
+
+      arguments:
+      * 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.
+      * is_hidden -- whether the script is "hidden" or not. Defaults to False.
+      """
+      super ( HookScriptBase, self ).__init__()
 
-   def __init__ ( self, fspath, filename=None ):
-      super ( HookScript, self ).__init__()
       fname = (
          filename if filename is not None else os.path.basename ( fspath )
       )
 
-      self.fspath  = fspath
-      self.name    = os.path.splitext ( fname )[0] or fname
-      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]
-         self.is_hidden      = static_entry[2]
+      self.filename = fname
+
+      if priority is True:
+         prio_str, dash, remainder = fname.partition ( '-' )
+         if prio_str and dash and remainder:
+            try:
+               prio = int ( prio_str, 10 )
+            except ValueError:
+               self.priority = None
+            else:
+               self.priority = prio
+               fname         = remainder
+         else:
+            self.priority = None
       else:
-         self.default_events = False
-         self.priority       = None
-         self.is_hidden      = False
-   # --- end of __init__ (...) ---
+         self.priority = priority
 
-   def is_visible ( self ):
-      return not self.is_hidden and (
-         self.priority is None or self.priority >= 0
-      )
-   # --- end of is_visible (...) ---
+      self.name      = os.path.splitext ( fname )[0]
+      self.fspath    = fspath
+      self.is_hidden = is_hidden
+   # --- end of __init__ (...) ---
 
    def __str__ ( self ):
       yesno = lambda k: 'y' if k else 'n'
@@ -54,6 +144,118 @@ class HookScript ( object ):
       )
    # --- end of __str__ (...) ---
 
+   def get_static_info ( self ):
+      return roverlay.static.hookinfo.get ( self.name, None )
+   # --- end of get_static_info (...) ---
+
+   def is_visible ( self ):
+      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 (...) ---
+
+   @roverlay.util.objects.abstractmethod
+   def get_dest_name ( self, *args, **kwargs ):
+      pass
+   # --- end of get_dest_name (...) ---
+
+# --- end of HookScriptBase ---
+
+
+class UserHookScript ( HookScriptBase ):
+
+   def __init__ ( self, fspath, filename=None, event=None ):
+      super ( UserHookScript, self ).__init__ (
+         fspath, filename=filename, priority=True
+      )
+
+      self.hook_script_fspath = os.path.realpath ( self.fspath )
+      self.hook_script_ref    = (
+         False if not os.path.islink ( self.fspath ) else None
+      )
+
+      self.event = event
+   # --- end of __init__ (...) ---
+
+   def set_hookscript ( self, script_obj, strict=True ):
+      if script_obj and self.hook_script_ref is False:
+         raise Exception (
+            "user hook script {} is not a link!".format ( self.fspath )
+         )
+      elif script_obj is None or script_obj is False:
+         self.hook_script_ref = False
+
+      else:
+         self.hook_script_ref = script_obj.get_ref()
+         script_obj.add_user_script ( self )
+   # --- end of set_hookscript (...) ---
+
+   def has_hookscript ( self ):
+      return self.hook_script_ref is not None
+   # --- end of has_hookscript (...) ---
+
+   def get_hookscript ( self ):
+      ref = self.hook_script_ref
+      if ref is False:
+         return None
+      elif ref is None:
+         raise roverlay.util.objects.ObjectDisappeared()
+      else:
+         return ref.deref_safe()
+   # --- end of get_hookscript (...) ---
+
+   def get_hookscript_path ( self ):
+      return self.hook_script_fspath
+   # --- end of get_hookscript_path (...) ---
+
+   def get_dest_name ( self ):
+      return self.filename
+   # --- end of get_dest_name (...) ---
+
+# --- end of UserHookScript ---
+
+
+class HookScript ( HookScriptBase ):
+
+   def __init__ ( self, fspath, filename=None ):
+      super ( HookScript, self ).__init__ ( fspath, filename=filename )
+
+      static_entry = self.get_static_info()
+      if static_entry is not None:
+         self.default_events = static_entry[0]
+         self.priority       = static_entry[1]
+         self.is_hidden      = static_entry[2]
+      else:
+         self.default_events = False
+
+      self.user_script_refs = set()
+   # --- end of __init__ (...) ---
+
+   def add_user_script ( self, user_script ):
+      self.user_script_refs.add ( user_script.get_ref() )
+   # --- end of add_user_script (...) ---
+
+   def iter_user_scripts ( self, ignore_missing=True ):
+      if ignore_missing:
+         for ref in self.user_script_refs:
+            obj = ref.deref_unsafe()
+            if obj is not None:
+               yield obj
+      else:
+         for ref in self.user_script_refs:
+            yield obj.deref_safe()
+   # --- end of iter_user_scripts (...) ---
+
    def set_priority_from_generator ( self, number_gen, only_if_unset=True ):
       if self.priority is None:
          self.priority = next ( number_gen )
@@ -78,53 +280,47 @@ class HookScript ( object ):
       )
    # --- end of get_dest_name (...) ---
 
+   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 HookScriptDir ( object ):
+class HookScriptDirBase ( roverlay.util.objects.Referenceable ):
+
+   HOOK_SCRIPT_CLS = None
 
    def __init__ ( self, root ):
-      super ( HookScriptDir, self ).__init__()
+      super ( HookScriptDirBase, self ).__init__()
 
-      self.root      = root
-      self._scripts  = collections.OrderedDict()
+      self.root     = root
+      self.scripts  = collections.OrderedDict()
+      self.writable = None
    # --- end of __init__ (...) ---
 
    def __bool__ ( self ):
-      return bool ( self._scripts )
+      return bool ( self.scripts )
    # --- end of __bool__ (...) ---
 
+   def get_fspath ( self, relpath=None ):
+      if relpath:
+         return self.root + os.sep + str ( relpath )
+      else:
+         return self.root
+   # --- end of get_fspath (...) ---
+
    def get_script ( self, name ):
-      script = self._scripts [name]
+      script = self.scripts [name]
       return script if script.is_visible() else None
    # --- end of get_scripts (...) ---
 
-   def iter_default_scripts ( self, unpack=False ):
-      if unpack:
-         for script in self._scripts.values():
-            if script.default_events:
-               for event in script.default_events:
-                  yield ( event, script )
-      else:
-         for script in self._scripts.values():
-            if script.default_events:
-               yield script
-   # --- end of iter_default_scripts (...) ---
-
-   def get_default_scripts ( self ):
-      scripts = dict()
-      for event, script in self.iter_default_scripts ( unpack=True ):
-         if event not in scripts:
-            scripts [event] = [ script ]
-         else:
-            scripts [event].append ( script )
-
-      return scripts
-   # --- end of get_default_scripts (...) ---
-
    def iter_scripts ( self ):
-      for script in self._scripts.values():
+      for script in self.scripts.values():
          if script.is_visible():
             yield script
    # --- end of iter_scripts (...) ---
@@ -136,80 +332,354 @@ class HookScriptDir ( object ):
       except OSError as oserr:
          if oserr.errno != errno.ENOENT:
             raise
-
       else:
+         HOOK_CLS = self.HOOK_SCRIPT_CLS
          for fname in filenames:
             fspath = root + os.sep + fname
             if os.path.isfile ( fspath ):
-               script_obj = HookScript ( fspath, fname )
-               self._scripts [script_obj.name] = script_obj
+               script_obj = HOOK_CLS ( fspath, filename=fname )
+               self.scripts [script_obj.name] = script_obj
    # --- end of scan (...) ---
 
+# --- end of HookScriptDirBase ---
+
+
+class NestedHookScriptDirBase ( HookScriptDirBase ):
+   SUBDIR_CLS       = collections.OrderedDict
+   DIRNAMES_IGNORE  = frozenset({ '.*', })
+   FILENAMES_IGNORE = frozenset({ '.*', })
+
+   def dirname_filter ( self, dirname, _fnmatch=fnmatch.fnmatch ):
+      for pattern in self.DIRNAMES_IGNORE:
+         if _fnmatch ( dirname, pattern ):
+            return False
+      return True
+   # --- end of dirname_filter (...) ---
+
+   def get_script ( self, name ):
+      return [
+         script for script in self.iter_scripts() if script.name == name
+      ]
+   # --- end of get_script (...) ---
+
+   def filename_filter ( self, filename, _fnmatch=fnmatch.fnmatch ):
+      for pattern in self.FILENAMES_IGNORE:
+         if _fnmatch ( filename, pattern ):
+            return False
+      return True
+   # --- end of filename_filter (...) ---
+
+   def create_hookscript ( self, fspath, filename, root ):
+      return self.HOOK_SCRIPT_CLS ( fspath, filename=filename )
+   # --- end of create_hookscript (...) ---
+
+   def scan ( self, prune_empty=True ):
+      SUBDIR_CLS = self.SUBDIR_CLS
+
+      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=True,
+      )
+
+      for event, hook in self.iter_scripts():
+         if hook.event is None:
+            hook.event = event
+   # --- end of scan (...) ---
+
+   def iter_scripts ( self ):
+      # roverlay uses per-event subdirs containing hook files
+      SUBDIR_CLS = self.SUBDIR_CLS
+      for event, subdir in self.scripts.items():
+         if isinstance ( subdir, SUBDIR_CLS ):
+            for hook in subdir.values():
+               if isinstance ( hook, HookScriptBase ) and hook.is_visible():
+               #if not isinstance ( hook, SUBDIR_CLS ):
+                  yield ( event, hook )
+   # --- end of iter_scripts (...) ---
+
+# --- end of NestedHookScriptDirBase ---
+
+
+class UserHookScriptDir ( NestedHookScriptDirBase ):
+
+   HOOK_SCRIPT_CLS = UserHookScript
+
+   def create_hookdir_refs ( self,
+      hook_dir, overwrite=False, compare_fspath=True
+   ):
+      for event, user_script in self.iter_scripts():
+         if overwrite or not user_script.has_hookscript():
+            try:
+               hook = hook_dir.get_script ( user_script.name )
+            except KeyError:
+               pass
+            else:
+               if hook is not None and (
+                  not compare_fspath or user_script.fspath == hook.fspath
+               ):
+                  user_script.set_hookscript ( hook )
+   # --- end of create_hookdir_refs (...) ---
+
+   def make_hookdir_refs ( self, hook_dir, overwrite=False ):
+      # try exact fs path matches first, then use name-based ones
+      self.create_hookdir_refs ( hook_dir, compare_fspath=True )
+      self.create_hookdir_refs ( hook_dir, compare_fspath=False )
+   # --- end of make_hookdir_refs (...) ---
+
+   def register_hook_link_unsafe ( self, event_name, hook, link, link_name ):
+      subdir = self.scripts.get ( event_name, None )
+      if subdir is None or link_name not in subdir:
+         if subdir is None:
+            subdir = self.SUBDIR_CLS()
+            self.scripts [event_name] = subdir
+         # -- end if
+
+         entry = self.HOOKDIR_CLS ( link, filename=link_name )
+         subdir [link_name] = entry
+      else:
+         entry = subdir [link_name]
+      # -- end if
+
+      entry.set_hookscript ( hook, strict=False )
+      if entry.event is None:
+         entry.event = event_name
+      elif entry.event != event_name:
+         raise AssertionError ( "entry.event != event_name" )
+      return True
+   # --- end of register_hook_link_unsafe (...) ---
+
+   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 ---
+
+
+class HookScriptDir ( HookScriptDirBase ):
+
+   HOOK_SCRIPT_CLS = HookScript
+
+   def iter_linked ( self ):
+      # 2-tuple ( hook_script, list ( linked_user_scripts ) )
+      for script in self.iter_scripts():
+         yield ( script, list ( script.iter_user_scripts() ) )
+   # --- end of iter_linked (...) ---
+
+   def iter_default_scripts ( self, unpack=False ):
+      if unpack:
+         for script in self.iter_scripts():
+            if script.default_events:
+               for event in script.default_events:
+                  yield ( event, script )
+      else:
+         for script in self.iter_scripts():
+            if script.default_events:
+               yield script
+   # --- end of iter_default_scripts (...) ---
+
+   def get_default_scripts ( self ):
+      return roverlay.util.dictwalk.dictmerge (
+         self.iter_default_scripts ( unpack=True ),
+         get_value=lambda kv:kv[1]
+      )
+   # --- end of get_default_scripts (...) ---
+
 # --- end of HookScriptDir ---
 
 
+
 class SetupHookEnvironment (
    roverlay.setupscript.baseenv.SetupSubEnvironment
 ):
 
    NEEDS_CONFIG_TREE = True
 
-   def setup ( self ):
-      additions_dir = self.config.get ( 'OVERLAY.additions_dir', None )
-      if additions_dir:
-         self.user_hook_root = os.path.join ( additions_dir, 'hooks' )
-         self.writable       = self.setup_env.private_file.check_writable (
-            self.user_hook_root + os.sep + '.keep'
+   def format_hook_info_lines ( self,
+      info, sort_info=True, append_newline=False
+   ):
+      max_name_len = min ( 30, max ( len(x[0]) for x in info ) )
+
+      event_names  = set()
+      for name, ev_prio in info:
+         event_names.update ( item[0] for item in ev_prio )
+
+      event_words = [
+         ( ev, (4+len(ev)) * ' ' ) for ev in sorted ( event_names )
+      ]
+
+      if sort_info:
+         my_info = sorted (
+            info,
+            key=lambda k: ( not k[1], k[0] )
          )
       else:
-         self.user_hook_root = None
-         self.writable       = None
+         my_info = info
+
+      for name, event_prio_list in my_info:
+         events   = dict ( event_prio_list )
+         get_prio = lambda p: ( "UU" if p is None else p )
+
+         yield "{name:>{nlen}} | {ev}".format (
+            name=name, nlen=max_name_len,
+            ev=' '.join (
+               (
+                  "{name}({prio:0>2})".format (
+                     name=ev, prio=get_prio ( events[ev] )
+                  ) if ev in events else replacement
+                  for ev, replacement in event_words
+               )
+            )
+         ).rstrip()
+      # -- end for
+
+      if append_newline:
+         yield ""
+   # --- end of format_hook_info_lines (...) ---
+
+   def get_hook_root_info ( self, nonlinked_only=False ):
+      if nonlinked_only:
+         return [
+            ( script.name, [] )
+            for script, user_scripts in self.hook_root.iter_linked()
+               if not user_scripts
+         ]
+      else:
+         return [
+            (
+               script.name,
+               [ ( s.event or "undef", s.priority ) for s in user_scripts ]
+            )
+            for script, user_scripts in self.hook_root.iter_linked()
+         ]
+   # --- end of get_hook_root_info (...) ---
+
+   def get_user_hook_info ( self ):
+      return [
+         ( s.name, [ ( s.event or "undef", s.priority ) ] )
+         for event, s in self.user_hooks.iter_scripts()
+      ]
+   # --- end of get_user_hook_info (...) ---
+
+   def gen_hook_info_lines ( self, append_newline=True ):
+      info = (
+         self.get_user_hook_info()
+         + self.get_hook_root_info ( nonlinked_only=True )
+      )
+      for line in self.format_hook_info_lines (
+         info, append_newline=append_newline
+      ):
+         yield line
+   # --- end of gen_hook_info_lines (...) ---
+
+   def setup ( self ):
+      self.hook_overwrite_control = self.setup_env.hook_overwrite
+
+      additions_dir = self.config.get ( 'OVERLAY.additions_dir', None )
 
       self.hook_root = HookScriptDir (
          os.path.join ( self.setup_env.data_root, 'hooks' )
       )
       self.hook_root.scan()
       self._prio_gen = roverlay.util.counter.UnsafeCounter ( 30 )
+
+
+      if additions_dir:
+         self.user_hooks = UserHookScriptDir (
+            os.path.join ( additions_dir, 'hooks' )
+         )
+         self.user_hooks.writable = (
+            self.setup_env.private_file.check_writable (
+               self.user_hooks.get_fspath ( '.keep' )
+            )
+         )
+         self.user_hooks.scan()
+         if self.hook_root:
+            self.user_hooks.make_hookdir_refs ( self.hook_root )
+      else:
+         self.user_hooks = None
    # --- end of setup (...) ---
 
-   def _link_hook ( self, source, link ):
+   def check_link_allowed ( self, source, link, link_name ):
       if os.path.lexists ( link ):
-         linkdest = os.path.realpath ( link )
+         allow_overwrite = False
+
+         skip_message = (
+            'Skipping activation of hook {!r} - '.format ( link_name )
+         )
+         ov_message = 'Overwriting hook {!r} - '.format ( link_name )
+
+
+         if os.path.islink ( link ):
+            linkdest = os.path.realpath ( link )
+
+            if linkdest == source or linkdest == os.path.realpath ( source ):
+               self.info ( skip_message + "already set up.\n" )
+               allow_overwrite = None
 
-         message = 'Skipping activation of hook {!r} - '.format ( link )
+            elif os.path.exists ( link ):
+               if self.hook_overwrite_control.overwrite_symlinks():
+                  self.info ( ov_message + "symlink.\n" )
+                  allow_overwrite = True
+               else:
+                  self.error ( skip_message + "symlink.\n" )
 
-         if linkdest == source or linkdest == os.path.realpath ( source ):
-            self.info ( message + "already set up.\n" )
-            return True
+            elif self.hook_overwrite_control.overwrite_dead_symlinks():
+               self.info ( ov_message + "broken symlink.\n" )
+               allow_overwrite = True
+
+            else:
+               self.error ( skip_message + "broken symlink.\n" )
+
+         elif os.path.isfile ( link ):
+            if self.hook_overwrite_control.overwrite_all():
+               self.error ( ov_message + "file.\n" )
+               allow_overwrite = True
+            else:
+               self.error ( skip_message + "file.\n" )
 
-         elif link != linkdest:
-            # symlink or link was relative
-            self.error ( message + "is a link to another file.\n" )
          else:
-            self.error ( message + "exists, but is not a link.\n" )
+            self.error ( skip_message + "not a file!\n" )
 
-         return None
+         # -- end if
+
+         return allow_overwrite
       else:
-         return self.setup_env.private_file.symlink ( source, link )
-   # --- end of _link_hook (...) ---
+         return True
+   # --- end of check_link_allowed (...) ---
 
    def link_hooks_v ( self, event_name, hooks ):
       success = False
 
-      if self.writable and self.user_hook_root:
-         destdir = self.user_hook_root + os.sep + event_name
+      if self.user_hooks is not None and self.user_hooks.writable:
+
+         destdir = self.user_hooks.get_fspath ( event_name )
          self.setup_env.private_dir.dodir ( destdir )
 
+         # note that there is a race condition when users manipulate their
+         # hook dir while running roverlay-setup
          to_link = []
          for script in hooks:
             script.set_priority_from_generator ( self._prio_gen )
-            to_link.append (
-               ( script.fspath, destdir + os.sep + script.get_dest_name() )
-            )
-
-         success = True
-         for source, link_name in to_link:
-            if self._link_hook ( source, link_name ) is False:
+            dest_name = script.get_dest_name()
+            link = destdir + os.sep + dest_name
+
+            if self.check_link_allowed ( script.fspath, link, dest_name ):
+               to_link.append ( ( script, dest_name, link ) )
+         # -- end for
+
+         register_link = self.user_hooks.register_hook_link_unsafe
+         symlink       = self.setup_env.private_file.symlink
+         success       = True
+
+         for script, dest_name, link in to_link:
+            have_link = symlink ( script.fspath, link )
+            if have_link:
+               register_link ( event_name, script, link, dest_name )
+            elif have_link is not None:
                success = False
       # -- end if
 
@@ -230,4 +700,9 @@ class SetupHookEnvironment (
       return success
    # --- end of enable_defaults (...) ---
 
+   def run ( self ):
+      # TODO
+      self.info ( '\n'.join ( self.gen_hook_info_lines() ) )
+   # --- end of run (...) ---
+
 # --- end of SetupHookEnvironment ---

diff --git a/roverlay/setupscript/initenv.py b/roverlay/setupscript/initenv.py
index febe39e..5e511f8 100644
--- a/roverlay/setupscript/initenv.py
+++ b/roverlay/setupscript/initenv.py
@@ -101,6 +101,9 @@ class SetupInitEnvironment (
          )
 
       yield ( "enable default hooks", get_option ( 'want_default_hooks' ) )
+
+      yield ( "overwrite hooks", self.setup_env.hook_overwrite.get_str() )
+
       yield ( "additional config variables", get_option ( 'config_vars' ) )
    # --- end of gen_pretend_options (...) ---
 

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index e094951..5a55515 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -50,14 +50,18 @@ def arg_stdout_or_fs ( value ):
 class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
    MULTIPLE_COMMANDS = False
    COMMAND_DESCRIPTION = {
-      'init':     'initialize roverlay\'s config and filesystem layout',
-      'mkconfig': 'generate a config file',
+      'init'     : 'initialize roverlay\'s config and filesystem layout',
+      'mkconfig' : 'generate a config file',
+      'hooks'    : 'manage hook files',
    }
    DEFAULT_COMMAND = "init"
 
-   COMMANDS_WITH_PRETEND = frozenset ({ 'init', })
+   COMMANDS_WITH_PRETEND = frozenset ({ 'init', 'hooks', })
 
-   SETUP_TARGETS = ( 'version', 'actions', 'setup', 'config', 'init', )
+   SETUP_TARGETS = (
+      'usage', 'version',
+      'actions', 'setup', 'config', 'init', 'hooks',
+   )
    PARSE_TARGETS = ( 'actions', 'setup', 'config', 'init', )
 
 
@@ -214,6 +218,25 @@ class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
             )
    # --- end of parse_init (...) ---
 
+   def setup_hooks ( self ):
+      arg = self.add_argument_group (
+         "hooks", title="options for managing hooks"
+      )
+
+      arg (
+         "--overwrite-hooks", dest='hook_overwrite',
+         default="dead", const="links", nargs="?", metavar="<when>",
+         choices=[ 'none', 'dead', 'links', 'all', ],
+         flags=self.ARG_WITH_DEFAULT,
+         help=(
+            'control hook overwrite behavior '
+            '(%(choices)s; \'%(const)s\' if specified without an arg)'
+         ),
+      )
+
+      return arg
+   # --- end of setup_hooks (...) ---
+
 # --- end of SetupArgParser ---
 
 
@@ -366,6 +389,11 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
       self.data_root      = expanduser ( options ['data_root'] )
       self.conf_root      = expanduser ( options ['conf_root'] )
       self.user_conf_root = expanduser ( options ['private_conf_root'] )
+      self.hook_overwrite = (
+         roverlay.setupscript.hookenv.HookOverwriteControl.from_str (
+            options ['hook_overwrite']
+         )
+      )
 
 
       self.fs_ops_virtual = {
@@ -470,6 +498,8 @@ class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
    def default_main ( self ):
       if self.wants_command ( "mkconfig" ):
          self.write_config_file ( self.options ['output'] )
+      elif self.wants_command ( "hooks" ):
+         self.get_hook_env().run()
       elif self.wants_command ( "init" ):
          self.get_init_env().run()
    # --- end of default_main (...) ---


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/
@ 2013-09-11 14:50 André Erdmann
  0 siblings, 0 replies; 12+ messages in thread
From: André Erdmann @ 2013-09-11 14:50 UTC (permalink / raw
  To: gentoo-commits

commit:     b33e905caa08f4912c5ecc1813da659688513497
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Sep 11 13:09:38 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Sep 11 13:09:38 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b33e905c

add copyright note to roverlay/setupscript/*.py

---
 roverlay/setupscript/__init__.py | 3 +++
 roverlay/setupscript/baseenv.py  | 3 +++
 roverlay/setupscript/hookenv.py  | 3 +++
 roverlay/setupscript/initenv.py  | 4 ++++
 roverlay/setupscript/runtime.py  | 3 +++
 5 files changed, 16 insertions(+)

diff --git a/roverlay/setupscript/__init__.py b/roverlay/setupscript/__init__.py
index 740a69c..874cd6a 100644
--- a/roverlay/setupscript/__init__.py
+++ b/roverlay/setupscript/__init__.py
@@ -1,2 +1,5 @@
 # R overlay -- setup script
 # -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.

diff --git a/roverlay/setupscript/baseenv.py b/roverlay/setupscript/baseenv.py
index 349d077..eb05764 100644
--- a/roverlay/setupscript/baseenv.py
+++ b/roverlay/setupscript/baseenv.py
@@ -1,5 +1,8 @@
 # R overlay -- setup script, base env
 # -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
 
 class SetupSubEnvironment ( object ):
 

diff --git a/roverlay/setupscript/hookenv.py b/roverlay/setupscript/hookenv.py
index 9c5fedb..e07b4e7 100644
--- a/roverlay/setupscript/hookenv.py
+++ b/roverlay/setupscript/hookenv.py
@@ -1,5 +1,8 @@
 # R overlay -- setup script, env for managing hooks
 # -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
 
 import collections
 import errno

diff --git a/roverlay/setupscript/initenv.py b/roverlay/setupscript/initenv.py
index f07953a..febe39e 100644
--- a/roverlay/setupscript/initenv.py
+++ b/roverlay/setupscript/initenv.py
@@ -1,5 +1,8 @@
 # R overlay -- setup script, env for the "init" command
 # -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
 
 import os
 import textwrap
@@ -17,6 +20,7 @@ class SetupInitEnvironment (
    roverlay.setupscript.baseenv.SetupSubEnvironment
 ):
 
+   # ( action_name, can_be_skipped )
    ACTIONS = (
       ( 'pretend', False ),
       ( 'prepare_config_file', False ),

diff --git a/roverlay/setupscript/runtime.py b/roverlay/setupscript/runtime.py
index 9ba3eec..e094951 100644
--- a/roverlay/setupscript/runtime.py
+++ b/roverlay/setupscript/runtime.py
@@ -1,5 +1,8 @@
 # R overlay -- setup script, runtime
 # -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
 
 from __future__ import print_function
 


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-04-01 16:38 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-19 15:00 [gentoo-commits] proj/R_overlay:master commit in: roverlay/setupscript/ André Erdmann
  -- strict thread matches above, loose matches on Subject: below --
2014-04-01 16:38 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox