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

commit:     033f6e38ee070ee1e71563bbc8d3a308604706e0
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue May 29 17:00:56 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue May 29 17:00:56 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=033f6e38

roverlay, fileio: add possibility to ignore packages with unsuitable description data (os type); rename _verify_read_data -> _parse_read_data
	modified:   fileio.py

---
 roverlay/fileio.py |  115 +++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 83 insertions(+), 32 deletions(-)

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 6e905b9..5d13cf8 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -49,7 +49,7 @@ class DescriptionReader:
 		a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
 		Then, a new iteration over the field map compares field_identifier
 		with all aliases until the first case-(in)sensitive match (-> immediate return).
-		An emptry string will be returned if none of the above searches succeed.
+		None will be returned if none of the above searches succeed.
 
 		In other words: this method decides whether a field_identifier will be used and if so,
 		with which name.
@@ -224,11 +224,13 @@ class DescriptionReader:
 			package_version = package_version,
 		)
 
-
-
 	@classmethod
-	def _verify_read_data ( self, read_data ):
-		"""Verifies and fixes (e.g. add default values) read data"""
+	def _parse_read_data ( self, read_data ):
+		"""Verifies and parses/fixes read data.
+
+		arguments:
+		* read_data -- data from file, will be modified
+		"""
 
 		def stats ( data ):
 			"""Temporary function that prints some info about the given data."""
@@ -239,49 +241,92 @@ class DescriptionReader:
 			logging.write ( "=== end of list ===\n" )
 			del field
 
+		def _value_in_strlist ( _val, _list, case_insensitive=True ):
+			"""Returns true if value is in the given list."""
+			el = None
+			if case_insensitive:
+				lowval = _val.lower()
+				for el in _list:
+					if el.lower() == lowval:
+						return True
+				del lowval
+			else:
+				for el in _list:
+					if el == _val:
+						return True
+
+			del el
+			return False
+
+
 		stats ( read_data )
 
-		# "finalize" data
-		logging.write ( "Fixing data...\n" )
 		field = None
 
-		# join values to a single str
+		# insert default values
+		for field in const.DESCRIPTION_FIELD_MAP.keys():
+			if not field in read_data and 'default_value' in const.DESCRIPTION_FIELD_MAP [field]:
+				read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
+
+		# join values to a single string
 		for field in self._get_fields_with_flag ( 'joinValues' ):
 			if field in read_data.keys():
 				read_data [field] = ' ' . join ( read_data [field] )
 
-		# verify that all necessary fields have been added and are set
-		missing_fields = dict()
+		# ensure that all mandatory fields are set
+		missing_fields = list()
+
 		for field in self._get_fields_with_flag ( 'mandatory' ):
 			if field in read_data:
 				if not len (read_data [field]):
-					missing_fields [field] = 'unset'
+					missing_fields.append ( field )
 			else:
-				missing_fields [field] = 'missing'
+				missing_fields.append ( field )
 
-		del field
 
-		if len (missing_fields):
+
+
+		# check for fields that allow only certain values
+		unsuitable_fields = list()
+
+		for field in read_data.keys():
+			# skip _fileinfo
+			if field  != '_fileinfo':
+				if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
+					if not _value_in_strlist ( read_data [field],
+						const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
+					): unsuitable_fields.append ( field )
+
+
+		stats ( read_data )
+
+
+
+		valid = True
+
+		if len ( missing_fields ):
+			valid = False
+
 			logging.write (
 				"Verification of mandatory fields failed, the result leading to this was: " +
-				str (missing_fields) + "\n"
+				str ( missing_fields ) + "\n"
 			)
 
 			#<raise custom exception>
 			raise Exception ("^^^look above")
 
-		del missing_fields
+		if len ( unsuitable_fields ):
+			valid = False
 
-		# add/insert default values
-		for field in const.DESCRIPTION_FIELD_MAP.keys():
-			if not field in read_data and 'default_value' in const.DESCRIPTION_FIELD_MAP [field]:
-				read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
-
-
-		stats ( read_data )
+			logging.write (
+				"Some fields have values that forbid further parsing, the result leading to this was: " +
+					str ( unsuitable_fields ) + "\n"
+				)
 
-		return True
+		del missing_fields
+		del field
 
+		return valid
 
 	@classmethod
 	def readfile ( self, filepath ):
@@ -296,18 +341,18 @@ class DescriptionReader:
 		-> split field values
 		-> filter out unwanted/useless fields
 
-		The return value is a dict "<field name> => <field value[s]>"
-		with <field value> as str and <field values> as list.
+		The return value is a dict { fileinfo , description_data } or None if
+		the read data are "useless" (not suited to create an ebuild for it,
+		e.g. if OS_TYPE is not unix).
 		"""
 
-		read_data = dict (
-			_ = DescriptionReader._get_fileinfo ( filepath )
-		)
+		read_data = dict ()
+		fileinfo = DescriptionReader._get_fileinfo ( filepath )
 
 
 		try:
 			desc_lines = DescriptionReader._get_desc_from_file (
-				filepath, read_data ['_'] ['package_name']
+				filepath, fileinfo ['package_name']
 			)
 
 
@@ -377,8 +422,14 @@ class DescriptionReader:
 		del sline, line, val, field_context
 
 
-		if self._verify_read_data ( read_data ):
-			return read_data
+		if self._parse_read_data ( read_data ):
+			logging.write ( '## success ##\n' )
+			logging.write ( ( str ( read_data ) ) )
+			return dict (
+				fileinfo = fileinfo,
+				description_data = read_data
+			)
 		else:
+			logging.write ( '## fail ##\n' )
 			return None
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2015-01-26 17:41 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2015-01-26 17:41 UTC (permalink / raw
  To: gentoo-commits

commit:     b8228327d5a2a2a0cf7ceed76b2ff1cb518f4236
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Dec 16 00:20:49 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Dec 16 00:20:49 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b8228327

roverlay/defaultscript: remove debug print()

---
 roverlay/defaultscript.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index cd8d1ae..9d3c157 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -92,8 +92,6 @@ def run_script_main ( installed ):
    if os.path.isfile ( script_file ) or os.sep in exe:
       exe = script_file
 
-   print ( "X___", exe)
-
    roverlay.core.default_helper_setup ( installed )
    roverlay.tools.shenv.run_script_exec (
       exe, "runscript", sys.argv[1:], use_path=True


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2015-01-26 17:41 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2015-01-26 17:41 UTC (permalink / raw
  To: gentoo-commits

commit:     4186b2408fd0537510047b17917b174acfef4ff2
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Dec 15 23:00:46 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Dec 15 23:00:48 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4186b240

roverlay/strutil: add unquote_all to __all__

---
 roverlay/strutil.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 76949fc..b4bf347 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -7,7 +7,7 @@
 """provides utility functions for string manipulation"""
 
 __all__ = [ 'ascii_filter', 'bytes_try_decode', 'fix_ebuild_name',
-   'pipe_lines', 'shorten_str', 'unquote', 'foreach_str',
+   'pipe_lines', 'shorten_str', 'unquote', 'unquote_all', 'foreach_str',
    'str_to_bool',
 ]
 


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

commit:     cdac4e5844a929ccf999a0e1b023c8076e8d3d9e
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 18 02:26:56 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 18 02:26:56 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=cdac4e58

add addition control to roverlay main script

add package rules to --print-package-rules, apply_rules, create

---
 roverlay/defaultscript.py |  4 ++++
 roverlay/runtime.py       | 51 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 2c0d1f2..cd8d1ae 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -133,6 +133,8 @@ def run_early_commands ( env ):
       package_rules = (
          roverlay.packagerules.rules.PackageRules.get_configured()
       )
+      env.add_addition_control_rules ( package_rules )
+
       print ( env.HLINE )
       print ( str ( package_rules ) )
       print ( env.HLINE )
@@ -206,6 +208,7 @@ def run_overlay_create ( env ):
    try:
       repo_list       = env.get_repo_list()
       overlay_creator = env.get_overlay_creator()
+      env.add_addition_control_to_overlay_creator()
 
       ebuild_import_nosync = env.option ( 'sync_imported' )
       if ebuild_import_nosync is None:
@@ -282,6 +285,7 @@ def run_apply_package_rules ( env ):
    FH        = None
 
    prules = roverlay.packagerules.rules.PackageRules.get_configured()
+   env.add_addition_control_rules ( prules )
 
    # track package rules
    prules.add_trace_actions()

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index 829940e..4d0e9c2 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -20,6 +20,10 @@ import roverlay.stats.collector
 import roverlay.util.objects
 import roverlay.recipe.easylogger
 
+import roverlay.packagerules.generators.addition_control
+from roverlay.packagerules.generators.addition_control import \
+   create_addition_control_package_rule
+
 import roverlay.config.tree
 import roverlay.config.const
 
@@ -202,6 +206,53 @@ class RuntimeEnvironment ( RuntimeEnvironmentBase ):
       return self._overlay_creator
    # --- end of get_overlay_creator (...) ---
 
+   def create_addition_control_rules ( self, default_category=None ):
+      kwargs = {}
+      def add_key ( k, _kwargs=kwargs, _options=self.options ):
+         _kwargs [k] = _options [k]
+
+      add_key ( "cmdline_package_revbump_on_collision" )
+      add_key ( "cmdline_package_force_replace" )
+      add_key ( "cmdline_package_replace_only" )
+
+      add_key ( "file_package_extended" )
+      add_key ( "file_ebuild_extended"  )
+
+      return create_addition_control_package_rule (
+         (
+            default_category
+               or self.config.get_or_fail ( 'OVERLAY.category' )
+         ),
+         **kwargs
+      )
+   # --- end of create_addition_control_rules (...) ---
+
+   def add_addition_control_rules (
+      self, package_rules, default_category=None
+   ):
+      add_control_rule = self.create_addition_control_rules (
+         default_category = default_category
+      )
+      package_rules.append_rule ( add_control_rule )
+   # --- end of add_addition_control_rules (...) ---
+
+   def add_addition_control_to_overlay_creator ( self ):
+      if not self._overlay_creator:
+         raise AssertionError ( "overlay creator not initialized." )
+      elif not getattr ( self._overlay_creator, 'package_rules', None ):
+         raise AssertionError ( "overlay creator has no package rules." )
+      # --
+
+      self.add_addition_control_rules (
+         self._overlay_creator.package_rules,
+         self._overlay_creator.overlay.default_category,
+      )
+
+      # + add addition_control object [FUTURE]
+
+   # --- end of add_addition_control_to_overlay_creator (...) ---
+
+
    def do_setup ( self ):
       self.do_setup_parser()
       self.do_setup_config()


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:wip/addition_control commit in: roverlay/
@ 2014-07-18  2:50 André Erdmann
  2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2014-07-18  2:50 UTC (permalink / raw
  To: gentoo-commits

commit:     c86aaac5aca70211bc346b13e8d2b1d8afd00eb6
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 18 02:49:22 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 18 02:49:22 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c86aaac5

roverlay/runtime: fix add_addition_control_rules()

---
 roverlay/runtime.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index 4d0e9c2..521eb0e 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -233,7 +233,12 @@ class RuntimeEnvironment ( RuntimeEnvironmentBase ):
       add_control_rule = self.create_addition_control_rules (
          default_category = default_category
       )
-      package_rules.append_rule ( add_control_rule )
+
+      if add_control_rule:
+         package_rules.append_rule ( add_control_rule )
+         return True
+      else:
+         return False
    # --- end of add_addition_control_rules (...) ---
 
    def add_addition_control_to_overlay_creator ( self ):
@@ -243,7 +248,7 @@ class RuntimeEnvironment ( RuntimeEnvironmentBase ):
          raise AssertionError ( "overlay creator has no package rules." )
       # --
 
-      self.add_addition_control_rules (
+      return self.add_addition_control_rules (
          self._overlay_creator.package_rules,
          self._overlay_creator.overlay.default_category,
       )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:wip/addition_control commit in: roverlay/
@ 2014-07-18  2:28 André Erdmann
  2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2014-07-18  2:28 UTC (permalink / raw
  To: gentoo-commits

commit:     fe530a21c5a873382f15ff9407e8af9e10270252
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 18 02:23:54 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 18 02:23:54 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=fe530a21

roverlay/argparser: add add-policy args to main script

not adding all PKG_* actions, just revbump-on-collision, force-replace and
replace-only, plus {package,ebuild}-list (read extended statements from files).

A typical usage scenario would be:
   roverlay --replace "pkg0" --revbump "cat/p2" --replace-only "*"
or
   roverlay --ebuild-list /tmp/my_list --replace-only "*"

---
 roverlay/argparser.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 706cf5f..c323ce3 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -12,6 +12,9 @@ import roverlay.core
 import roverlay.argutil
 import roverlay.util.objects
 
+import roverlay.overlay.abccontrol
+from roverlay.overlay.abccontrol import AdditionControlResult
+
 # lazy import
 from roverlay.argutil import \
    LOG_LEVELS, \
@@ -449,8 +452,65 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
          default=argparse.SUPPRESS, flags=self.ARG_WITH_DEFAULT,
          help="choose how Manifest files are created (ebuild(1) or internal)",
       )
+
+      self._setup_addition_control ( arg )
    # --- end of setup_overlay_creation (...) ---
 
+   def _setup_addition_control ( self, add_arg ):
+##      # all:
+##      for name in AdditionControlResult.PKG_DESCRIPTION_REVMAP, ~X~:
+
+      for variant in [ "package", ]:
+         for name, long_name in [
+            ( "revbump",         "revbump-on-collision"  ),
+            ( "replace",         "force-replace"         ),
+            ( "replace-only",    "replace-only"          ),
+         ]:
+            arg_opt = (
+               "--{variant}-{name}".format ( variant=variant, name=name )
+            )
+
+            dest_name = "{variant}_{aname}".format (
+               variant = variant,
+               aname   = long_name.replace ( "-", "_" )
+            )
+
+
+            add_arg (
+               arg_opt,
+               dest = "cmdline_" + dest_name,
+               metavar = "<{variant}>".format ( variant=variant ),
+               default = [],
+               action  = 'append',
+               help    = (
+                  'set add-policy for <{variant}> to {lname!r}'.format (
+                     variant = variant,
+                     lname   = long_name,
+                  )
+               )
+            )
+      # -- end for
+
+      for variant in [ "package", "ebuild" ]:
+         arg_opt   = "--{variant}-list".format ( variant=variant )
+         dest_name = "file_{variant}_extended".format ( variant=variant )
+
+         add_arg (
+            arg_opt,
+            dest     = dest_name,
+            default  = None,
+            flags    = self.ARG_WITH_DEFAULT|self.ARG_META_FILE,
+            type     = is_fs_file_or_void,
+            help     = (
+               "file that lists {variant} add-policy statements".format (
+                  variant=variant
+               )
+            )
+         )
+      # -- end for
+
+   # --- end of _setup_addition_control (...) ---
+
    def setup_remote_minimal ( self ):
       arg = self.add_argument_group ( "remote", title="sync options" )
 


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

commit:     3a25a91a514bfa52b3df508ecd32558cdc044ba5
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun 30 17:42:52 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun 30 17:42:52 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=3a25a91a

packageinfo, revbump(): add 'ebuild_only' param

---
 roverlay/packageinfo.py | 43 ++++++++++++++++++++++++-------------------
 1 file changed, 24 insertions(+), 19 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 9083d61..a6428d0 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -606,12 +606,14 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
       return self.hashdict
    # --- end of make_hashes (...) ---
 
-   def revbump ( self, newrev=None ):
+   def revbump ( self, newrev=None, ebuild_only=False ):
       """Do whatever necessary to revbump this pakages, that is set/update
       all data like src_uri_dest and ebuild_verstr.
 
       arguments:
-      * newrev -- new revision, (current rev + 1) is used if this is None
+      * newrev      -- new revision, (current rev + 1) is used if this is None
+      * ebuild_only -- if set and True: revbump the package only,
+                       keeping the distfile path as-is
       """
       rev     = self._info['rev'] + 1 if newrev is None else int ( newrev )
       rev_str = ( '-r' + str ( rev ) ) if rev > 0 else ''
@@ -619,26 +621,29 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
          '.'.join ( str ( k ) for k in self._info['version'] ) + rev_str
       )
 
-      # preserve destpath directory
-      #  (this allows to handle paths like "a/b.tar/pkg.tgz" properly)
-      #
-      old_destpath = self ['package_src_destpath'].rpartition ( os.path.sep )
-
-      # os.path.splitext does not "recognize" .tar.gz
-      fhead, ftar, fext = old_destpath[2].rpartition ( '.tar' )
-      if not ftar:
-         fhead, fext = os.path.splitext ( fext )
-
-      # FIXME: any way to get this reliably (+faster) done without a regex?
-      #  ( a,b,c=fhead.rpartition ( '-r' ); try int(c) ...; ?)
-      distfile = (
-         old_destpath[0] + old_destpath[1]
-         + self.EBUILDREV_REGEX.sub ( '', fhead ) + rev_str + ftar + fext
-      )
+      if not ebuild_only:
+         # preserve destpath directory
+         #  (this allows to handle paths like "a/b.tar/pkg.tgz" properly)
+         #
+         old_destpath = self ['package_src_destpath'].rpartition ( os.path.sep )
+
+         # os.path.splitext does not "recognize" .tar.gz
+         fhead, ftar, fext = old_destpath[2].rpartition ( '.tar' )
+         if not ftar:
+            fhead, fext = os.path.splitext ( fext )
+
+         # FIXME: any way to get this reliably (+faster) done without a regex?
+         #  ( a,b,c=fhead.rpartition ( '-r' ); try int(c) ...; ?)
+         distfile = (
+            old_destpath[0] + old_destpath[1]
+            + self.EBUILDREV_REGEX.sub ( '', fhead ) + rev_str + ftar + fext
+         )
+
+         self._info ['src_uri_dest']  = distfile
+      # -- end if <ebuild_only>
 
       self._info ['rev']           = rev
       self._info ['ebuild_verstr'] = vstr
-      self._info ['src_uri_dest']  = distfile
 
       return self
    # --- end of revbump (...) ---


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

commit:     9be2a6aaaac4f0377e3895787aef47ad0d8a93f3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May  7 01:17:54 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May  7 01:17:54 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9be2a6aa

not-installed: search for config file in PRJROOT

This allows to run
  roverlay.load_locate_config_file(False,load_main_only=True)
from "any" location if ROVERLAY_PRJROOT and PYTHONPATH are set properly.

---
 roverlay/core.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/roverlay/core.py b/roverlay/core.py
index d462f0f..2f4215b 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -155,11 +155,13 @@ def locate_config_file (
          if os.path.isfile ( cfg ):
             return cfg
 
-   elif os.path.exists ( CONFIG_FILE_NAME + '.local' ):
-      return CONFIG_FILE_NAME + '.local'
+   else:
+      config_dir = os.environ.get ( 'ROVERLAY_PRJROOT', os.getcwd() )
 
-   elif os.path.exists ( CONFIG_FILE_NAME ):
-      return CONFIG_FILE_NAME
+      for fname in ( CONFIG_FILE_NAME + '.local', CONFIG_FILE_NAME ):
+         fpath = config_dir + os.sep + fname
+         if os.path.exists ( fpath ):
+            return fpath
 
    return None
 # --- end of locate_config_file (...) ---


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

commit:     19ad4d4e8e73b7be7f8a81e86ffa83116adb2cf1
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Mar 31 17:13:10 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Mar 31 17:13:10 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=19ad4d4e

roverlay/argparser: fix

Pass **kwargs when creating the parser object.

---
 roverlay/argparser.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 2fa6ca1..706cf5f 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -84,6 +84,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
             argparse.RawDescriptionHelpFormatter
             if formatter_class is True else formatter_class
          ),
+         **kwargs
       )
    # --- end of create_new_parser (...) ---
 


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

commit:     e9c4b6176fcae0ee52ee1aa8112bb6b208c2bea7
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sun Feb 16 16:22:23 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sun Feb 16 16:27:44 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=e9c4b617

roverlay/core: also log python version on startup

---
 roverlay/core.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/roverlay/core.py b/roverlay/core.py
index 414e705..b8fe6a5 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -121,7 +121,12 @@ def load_config_file (
 
    if setup_logger:
       roverlay.recipe.easylogger.setup ( roverlay_config )
-      logging.getLogger().debug ( "roverlay version " + version )
+      my_logger = logging.getLogger()
+      my_logger.debug ( "roverlay version " + version )
+      my_logger.debug (
+         "python version {0}.{1}.{2}".format ( *sys.version_info )
+      )
+      del my_logger
 
    if not load_main_only:
       confloader.load_field_definition (


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

commit:     db2aa8720cb4c726551dc640f179189820a11d09
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Feb 15 18:56:53 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Feb 15 18:56:53 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=db2aa872

roverlay/fsutil.py, get_fs_dict(): fix

os.walk() should be called with my_root as dir, not initial_root (which is an
issue when initial_root is not an absolute path).
Not an issue for roverlay so far as get_fs_dict() gets called with abspaths
only.

---
 roverlay/fsutil.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index 309aadc..d0091c2 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -120,7 +120,7 @@ def get_fs_dict (
       1 + ( my_root.rfind ( os.sep ) if include_root else len ( my_root ) )
    )
 
-   for root, dirnames, filenames in os.walk ( initial_root ):
+   for root, dirnames, filenames in os.walk ( my_root ):
       if dirname_filter:
          dirnames[:] = [ d for d in dirnames if dirname_filter ( d ) ]
 


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

commit:     c220255d727063935f654df552f0b3767f504216
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Feb 15 18:54:37 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Feb 15 18:54:37 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c220255d

roverlay/strutil.py, unquote(): fix keep_going

unquote() needs to call itself with keep_going=True when operating recursively.

---
 roverlay/strutil.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 7569523..9799477 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -100,7 +100,7 @@ def unquote ( _str, keep_going=False ):
    chars  = '\"\''
 
    if _str [0] == _str [-1] and _str [0] in chars:
-      return unquote ( _str[1:-1] ) if keep_going else _str[1:-1]
+      return unquote ( _str[1:-1], True ) if keep_going else _str[1:-1]
 
    return _str
 # --- end of unquote (...) ---


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

commit:     6e862b4bc55db2053d797963c7589eb803b2bc11
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Jan 25 17:53:18 2014 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Jan 25 17:53:18 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6e862b4b

roverlay/core, default_helper_setup(): fix log_to_console

False == 0, so check whether log_to_console is False
(-> don't enforce console logging) or 0 (-> set log level to 0).

---
 roverlay/core.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/roverlay/core.py b/roverlay/core.py
index 7a30867..414e705 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -171,7 +171,9 @@ def default_helper_setup ( ROVERLAY_INSTALLED, log_to_console=True ):
       roverlay.recipe.easylogger.force_console_logging (
          log_level=logging.WARNING
       )
-   elif log_to_console or log_to_console == 0:
+   elif log_to_console or (
+      log_to_console == 0 and log_to_console is not False
+   ):
       roverlay.recipe.easylogger.force_console_logging (
          log_level=log_to_console
       )


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

commit:     c656c3a2e0c76b61e30ada38d7e88020358bfcee
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Dec 11 16:05:46 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Dec 11 16:05:46 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c656c3a2

log version on startup

---
 roverlay/core.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/roverlay/core.py b/roverlay/core.py
index 01066c8..7a30867 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -121,6 +121,7 @@ def load_config_file (
 
    if setup_logger:
       roverlay.recipe.easylogger.setup ( roverlay_config )
+      logging.getLogger().debug ( "roverlay version " + version )
 
    if not load_main_only:
       confloader.load_field_definition (


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

commit:     b6c99cf154217ce3afac99e38bb6417154de6b38
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Dec 11 17:56:53 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Dec 11 17:56:53 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b6c99cf1

roverlay/strutil: foreach_str()

---
 roverlay/strutil.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 10a4360..7569523 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -7,7 +7,7 @@
 """provides utility functions for string manipulation"""
 
 __all__ = [ 'ascii_filter', 'bytes_try_decode', 'fix_ebuild_name',
-   'pipe_lines', 'shorten_str', 'unquote',
+   'pipe_lines', 'shorten_str', 'unquote', 'foreach_str',
 ]
 
 import re
@@ -151,3 +151,10 @@ def bytes_try_decode (
    else:
       return byte_str
 # --- end of bytes_try_decode() ---
+
+def foreach_str ( func, _str ):
+   if isinstance ( _str, str ) or not hasattr ( _str, '__iter__' ):
+      return func ( str ( _str ) )
+   else:
+      return [ func(str(s)) for s in _str ]
+# --- end of foreach_str (...) ---


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

commit:     0e40ceb1def1dfb66aac5545a53eea27e82f9fe6
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Sep 23 13:11:44 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Sep 23 13:11:44 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0e40ceb1

roverlay-status: do not fail if db is missing

---
 roverlay/status.py | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/roverlay/status.py b/roverlay/status.py
index cb25edb..9ab00a3 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -322,18 +322,19 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 #            rrd_db=self.stats_db,
 #        )
 
-
-         # transfer db cache to template_vars
-         # * copy lastupdate
-         # * import values
-         #
-         self.set_template_vars (
-            self.stats_db.cache ['values'],
-            lastupdate=self.stats_db.cache ['lastupdate'],
-            STATS_DB_FILE=stats_db_file,
-            STATS_DB=DBStats ( self.stats_db.cache ),
-         )
-
+         if self.stats_db.cache:
+            # transfer db cache to template_vars
+            # * copy lastupdate
+            # * import values
+            #
+            self.set_template_vars (
+               self.stats_db.cache ['values'],
+               lastupdate=self.stats_db.cache ['lastupdate'],
+               STATS_DB_FILE=stats_db_file,
+               STATS_DB=DBStats ( self.stats_db.cache ),
+            )
+         else:
+            self.stats_db = None
       # -- end if
 
       self.do_setup_mako()


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

commit:     b26619285c74e85a7db260834da7cdda3bab0e2d
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 20 14:47:41 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 20 14:47:41 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b2661928

roverlay/fsutil: comments, cleanup

Also contains some fixes, e.g. handle "/" properly in walk_up().

---
 roverlay/fsutil.py | 668 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 565 insertions(+), 103 deletions(-)

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index 7fede96..309aadc 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -4,6 +4,7 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
+import abc
 import errno
 import functools
 import itertools
@@ -21,24 +22,54 @@ _OS_CHMOD = getattr ( os, 'lchmod', os.chmod )
 
 
 def walk_up ( dirpath, topdown=False, max_iter=None ):
-   path_elements = os.path.normpath ( dirpath ).split ( os.sep )
+   """Generator that yields all (partial..full) filesystem paths contained
+   in dirpath.
 
-   if path_elements:
-      p_start = 0 if path_elements[0] else 1
+   Examples:
+      walk_up (
+         "/a/b/c/d", topdown=False, max_iter=None
+      ) -> ( "/a/b/c/d", "/a/b/c", "/a/b", "/a", "/" )
 
-      if max_iter is None:
-         high = len ( path_elements )
-      else:
-         high = min ( max_iter + p_start, len ( path_elements ) )
+      walk_up ( "/" ) -> ( "/" )
 
+      walk_up ( "/b", topdown=True ) -> ( "/", "/b" )
 
-      if topdown:
-         for k in range ( p_start+1, high+1 ):
-            yield os.sep.join ( path_elements[:k] )
-      else:
-         for k in range ( high, p_start, -1 ):
-            yield os.sep.join ( path_elements[:k] )
+   arguments:
+   * topdown  -- Defaults to False.
+   * max_iter -- max number of paths to generate (None for unlimited)
+                  Defaults to None.
+   """
+   def iter_partial_paths ( _join_path=os.sep.join ):
+      fspath        = os.path.normpath ( dirpath ).rstrip ( os.sep )
+      path_elements = fspath.split ( os.sep )
+
+      if path_elements:
+         p_start = 0 if path_elements[0] else 1
+         high    = len ( path_elements )
+
+         if topdown:
+            if not path_elements[0]:
+               yield os.sep
+
+            for k in range ( p_start+1, high+1 ):
+               yield _join_path ( path_elements[:k] )
+         else:
+            for k in range ( high, p_start, -1 ):
+               yield _join_path ( path_elements[:k] )
+
+            if not path_elements[0]:
+               yield os.sep
+   # --- end of iter_partial_paths (...) ---
 
+   if max_iter is None:
+      for path in iter_partial_paths():
+         yield path
+   else:
+      for n, path in enumerate ( iter_partial_paths() ):
+         if n < max_iter:
+            yield path
+         else:
+            return
 # --- end of walk_up (...) ---
 
 def get_fs_dict (
@@ -46,7 +77,40 @@ def get_fs_dict (
    dirname_filter=None, filename_filter=None,
    include_root=False, prune_empty=False, file_key=None,
 ):
-   # http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
+   """Creates a dictionary-like object representing the filesystem structure
+   starting at the given root directory.
+
+   arguments:
+   * initial_root    -- root directory where os.walk should start
+   * create_item     -- Either a function that accepts 3 args (absolute file-
+                        system path, filename, absolute dirpath) and returns
+                        an object representing a file entry or None (resulting
+                        in None being the object). Defaults to None.
+   * dict_cls        -- dictionary class. Defaults to dict.
+                         Has to have a constructor accepting an iterable
+                         of 2-tuples (key,file entry or dict_cls object)
+                         if create_item is set, or a .fromkeys() method
+                         accepting an iterable of keys.
+                         Additionally, has to provide a __setitem__ method.
+   * dirname_filter  -- Either a function that returns True if a directory
+                        name is allowed and False if not, or None (do not
+                        restrict dirnames). Defaults to None.
+                        This also affects which directory paths are traversed.
+   * filename_filter -- Similar to dirname_filter, but can be used to ignore
+                        files. Defaults to None.
+   * include_root    -- Whether to make initial_root the dict root (False)
+                        or an item in the dict (True). In other words,
+                        controls whether the return value should be a dict
+                        starting at initial_root or a dict containing the
+                        initial_root dict. Defaults to False.
+   * prune_empty     -- Whether to remove directory entries without any items.
+                         Defaults to False.
+   * file_key        -- Either a function that returns the dict key for a
+                        file name or None (idendity, key==filename).
+
+   Inspired by http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
+   """
+   # TODO(could-do): max_depth=N
    fsdict         = dict_cls()
    my_root        = os.path.abspath ( initial_root )
 
@@ -88,15 +152,38 @@ def get_fs_dict (
 # --- end of get_fs_dict (...) ---
 
 def create_subdir_check ( parent, fs_sep=os.sep ):
+   """Returns a function that checks whether a given filesystem path is a
+   subpath of parent (where parent is a subpath of itself).
+
+   arguments:
+   * parent  -- parent filesystem path for which a subdir_check should be
+                created
+   * fs_sep  -- defaults to os.sep
+   """
    PARENT_PATH = parent.rstrip ( fs_sep ).split ( fs_sep )
 
-   def is_subdir ( dirpath ):
-      return all (
-         this == expect for this, expect in zip (
-            dirpath.rstrip ( fs_sep ).split ( fs_sep ),
-            PARENT_PATH
+   def is_subdir ( dirpath,
+      _path_el=PARENT_PATH, _path_len=len( PARENT_PATH ), _fs_sep=fs_sep
+   ):
+      """Returns True if the given filesystem path is a subpath of the
+      (predefined) parent path, else False.
+
+      arguments:
+      * dirpath   -- filesystem path to be checked
+      * _path_el  -- local variable containing information about the parent
+                     path. Shouldn't be set manually.
+      * _path_len -- local variable containing information about the length
+                     of the parent path. Shouldn't be set manually.
+      * _fs_sep   -- local variable that is a copy of fs_sep.
+                     Shouldn't be set manually.
+      """
+      dirpath_el = dirpath.rstrip ( _fs_sep ).split ( _fs_sep )
+      if len ( dirpath_el ) < _path_len:
+         return False
+      else:
+         return all (
+            this == expect for this, expect in zip ( dirpath_el, _path_el )
          )
-      )
    # --- end of is_subdir (...) ---
 
    return is_subdir
@@ -104,6 +191,15 @@ def create_subdir_check ( parent, fs_sep=os.sep ):
 
 
 def pwd_expanduser ( fspath, uid ):
+   """Expands "~" in a filesystem path to the given user's home directory.
+   Uses pwd to get that directory.
+
+   Returns: expanded path
+
+   arguments:
+   * fspath --
+   * uid    --
+   """
    if not fspath or fspath[0] != '~':
       return fspath
    elif len ( fspath ) < 2:
@@ -115,6 +211,32 @@ def pwd_expanduser ( fspath, uid ):
 # --- end of pwd_expanduser (...) ---
 
 def walk_copy_tree ( source, dest, subdir_root=False, **walk_kwargs ):
+   """Generator that iterates over the content of a filesystem tree starting
+   at source and compares it to the filesystem tree starting at dest (which
+   doesn't have to exist). The subdir_root can be used to control whether
+   source should be a subdir of dest or not (which means that
+   walk_copy_tree (source, dest, subdir_root=True) is identical to
+   walk_copy_tree (source, dest + os.sep + os.path.basename(source),
+   subdir_root=False)).
+
+   The items are 6-tuples (absolute path to the source directory,
+   absolute path to the dest dir, dir path relative to the source root,
+   list of directories, list of files, list of dirnames).
+
+   The dirnames list can be modified (slice assignment) in order to affect
+   the directories visited by os.walk().
+
+   The directories/files lists are lists of 2x2-tuples (
+      (abspath in source, stat in source), (abspath in dest, stat in dest)
+   ).
+
+   arguments:
+   * source        -- absolute path to the source root
+   * dest          -- absolute path to the dest root
+   * subdir_root   -- whether source should be a subdir of dest root or not
+                      Defaults to False.
+   * **walk_kwargs -- additional keyword arguments for os.walk()
+   """
    source_path   = os.path.abspath ( source )
    dest_path     = os.path.abspath ( dest )
    relpath_begin = 1 + (
@@ -139,9 +261,21 @@ def walk_copy_tree ( source, dest, subdir_root=False, **walk_kwargs ):
 # --- end of walk_copy_tree (...) ---
 
 class RWX ( object ):
+   """An object representing read/write/execute permissions."""
 
    @classmethod
    def from_str ( cls, s, strict=False ):
+      """Parses the given string and returns a new RWX object.
+
+      arguments:
+      * s      -- a string, e.g. "rwx" or "r-x"
+      * strict -- if True: expect that is a string with length >= 3, where
+                           read/write/executable is set to True if the
+                           first/second/third char is r/w/x and False
+                           otherwise.
+                  else   : set read/write/executable to True if s contains
+                           r/w/x and False otherwise
+      """
       readable, writable, executable = False, False, False
 
       if strict:
@@ -166,12 +300,27 @@ class RWX ( object ):
 
    @classmethod
    def from_bitmask ( cls, mode, rwx_bits ):
+      """Compares the given mode with a list of r/w/x bits and creates a
+      RWX object for it.
+
+      arguments:
+      * mode     -- integer containing r/w/x (and possible other) bits
+      * rwx_bits -- a list/tuple with at least three elements, where the
+                    first/second/third element is the read/write/executable bit
+      """
       return cls (
          mode & rwx_bits[0], mode & rwx_bits[1], mode & rwx_bits[2],
       )
    # --- end of from_bitmask (...) ---
 
    def __init__ ( self, readable, writable, executable ):
+      """RWX Constructor.
+
+      arguments:
+      * readable   -- bool
+      * writable   -- bool
+      * executable -- bool
+      """
       super ( RWX, self ).__init__()
       self.readable   = bool ( readable )
       self.writable   = bool ( writable )
@@ -179,6 +328,7 @@ class RWX ( object ):
    # --- end of __init__ (...) ---
 
    def __hash__ ( self ):
+      # could be removed (or replaced by a more proper __hash__ func)
       return id ( self )
    # --- end of __hash__ (...) ---
 
@@ -190,17 +340,30 @@ class RWX ( object ):
       )
    # --- end of __repr__ (...) ---
 
-   def get_str ( self, fillchar='-' ):
+   def get_str ( self, fillchar='-', rwx_chars="rwx" ):
+      """Returns a string similar to what ls would show ("rwx","r--",...).
+
+      arguments:
+      * fillchar  -- char that is used to express absense of read/write/exe
+                     Defaults to "-".
+      * rwx_chars -- a sequence of at least three chars. Defaults to "rwx."
+
+      """
       return (
-         ( 'r' if self.readable   else fillchar ) +
-         ( 'w' if self.writable   else fillchar ) +
-         ( 'x' if self.executable else fillchar )
+         ( rwx_chars[0] if self.readable   else fillchar ) +
+         ( rwx_chars[1] if self.writable   else fillchar ) +
+         ( rwx_chars[2] if self.executable else fillchar )
       )
    # --- end of get_str (...) ---
 
    __str__ = get_str
 
    def get_bitmask ( self, rwx_bits ):
+      """Returns an integer representing the rwx mode for the given rwx bits.
+
+      arguments:
+      * rwx_bits -- a list/tuple with at least three elements (r,w,x)
+      """
       ret = 0
       if self.readable:
          ret |= rwx_bits[0]
@@ -218,6 +381,8 @@ class RWX ( object ):
 
 
 class FsPermissions ( object ):
+   """An object representing read/write/execute permissions for users, groups
+   and others."""
 
    USR_BITS = ( stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR )
    GRP_BITS = ( stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP )
@@ -225,6 +390,13 @@ class FsPermissions ( object ):
 
    @classmethod
    def from_str ( cls, s, strict=False ):
+      """Returns a new permissions object for the given string.
+
+      arguments:
+      * s      -- the string, e.g. "rwxr-x---" or "r---x---w"
+      * strict -- affects how strings are parsed.
+                   see RWX.from_str() for details. Defaults to False.
+      """
       rwx_user   = RWX.from_str ( s[0:3], strict=strict )
       rwx_group  = RWX.from_str ( s[3:6], strict=strict )
       rwx_others = RWX.from_str ( s[6:9], strict=strict )
@@ -233,6 +405,11 @@ class FsPermissions ( object ):
 
    @classmethod
    def from_stat_mode ( cls, stat_mode ):
+      """Creates a permissions object for the given stat mode.
+
+      arguments:
+      * stat_mode -- stat mode as its returned by os.stat() (and others)
+      """
       return cls (
          RWX.from_bitmask ( stat_mode, cls.USR_BITS ),
          RWX.from_bitmask ( stat_mode, cls.GRP_BITS ),
@@ -241,6 +418,13 @@ class FsPermissions ( object ):
    # --- end of from_stat_mode (...) ---
 
    def __init__ ( self, rwx_user, rwx_group, rwx_others ):
+      """FsPermissions constructor.
+
+      arguments:
+      * rwx_user   -- RWX object
+      * rwx_group  -- RWX object
+      * rwx_others -- RWX object
+      """
       super ( FsPermissions, self ).__init__()
       self.user   = rwx_user
       self.group  = rwx_group
@@ -256,6 +440,11 @@ class FsPermissions ( object ):
    # --- end of __repr__ (...) ---
 
    def get_str ( self, fillchar='-' ):
+      """Returns an ls-like string.
+
+      arguments:
+      * fillchar -- defaults to "-"
+      """
       return "".join (
          rwx.get_str ( fillchar=fillchar )
          for rwx in ( self.user, self.group, self.others )
@@ -265,6 +454,7 @@ class FsPermissions ( object ):
    __str__ = get_str
 
    def get_stat_mode ( self ):
+      """Returns an integer that can be used for os.[l]chmod()."""
       return (
          self.user.get_bitmask   ( self.USR_BITS ) |
          self.group.get_bitmask  ( self.GRP_BITS ) |
@@ -278,12 +468,29 @@ class FsPermissions ( object ):
 # --- end of FsPermissions ---
 
 def get_stat_mode ( mode_str ):
+   """Converts a permissions string into an integer.
+
+   arguments:
+   * mode_str -- "rwx------" etc.
+   """
    return FsPermissions.from_str ( mode_str ).get_stat_mode()
 # --- end of get_stat_mode (...) ---
 
 class ChownChmod ( object ):
+   """An object for chown()/chmod() operations."""
+   # COULDFIX: remove / merge with AbstractFsOperations
+   #            this allows to recursively chmod files and dirs
 
    def __init__ ( self, uid=None, gid=None, mode=None, pretend=False ):
+      """ChownChmod constructor.
+
+      arguments:
+      * uid     -- uid for chown() or None (keep uid). Defaults to None.
+      * gid     -- gid for chown() or None (keep gid). Defaults to None.
+      * mode    -- int mode for chmod() or None (keep mode). Defaults to None.
+      * pretend -- whether to actually chown/chmod (False) or just print
+                   what would be done (True). Defaults to False.
+      """
       super ( ChownChmod, self ).__init__()
 
       self.pretend  = bool ( pretend )
@@ -324,17 +531,37 @@ class ChownChmod ( object ):
    # --- end of __init__ (...) ---
 
    def _nullfunc ( self, fspath ):
+      """No-op replacement for chown()/chmod().
+
+      arguments:
+      * fspath -- ignore
+      """
       return None
 
    def _do_chown ( self, fspath, _chown=_OS_CHOWN ):
+      """Calls chown(fspath)
+
+      arguments:
+      * fspath --
+      """
       _chown ( fspath, self.uid, self.gid )
       return self.chown_str.format ( fspath )
 
    def _do_chmod ( self, fspath, _chmod=_OS_CHMOD ):
+      """Calls chmod(fspath).
+
+      arguments:
+      * fspath --
+      """
       _chmod ( fspath, self.mode )
       return self.chmod_str.format ( fspath )
 
    def chown_chmod ( self, fspath ):
+      """Calls chmod(fspath) and chown(fspath).
+
+      arguments:
+      * fspath --
+      """
       # should be renamed to chmod_chown()
       return (
          self.chmod ( fspath ),
@@ -342,48 +569,50 @@ class ChownChmod ( object ):
       )
    # --- end of chown_chmod (...) ---
 
-   def chown_chmod_recursive ( self, root ):
-      chown = self.chown
-      chmod = self.chmod
-
-      if os.path.isfile ( root ):
-         yield chmod ( root )
-         yield chown ( root )
-
-      else:
-         for current_root, dirnames, filenames in os.walk ( root ):
-            yield chmod ( current_root )
-            yield chown ( current_root )
-
-            for filename in filenames:
-               fpath = current_root + os.sep + filename
-               yield chmod ( fpath )
-               yield chown ( fpath )
-   # --- end of chown_chmod_recursive (...) ---
-
 # --- end of ChownChmod ---
 
 
-def chown_chmod ( root, uid=None, gid=None, mode=None, pretend=False ):
-   return ChownChmod ( uid, gid, mode, pretend ).chown_chmod ( root )
-# --- end of chown_chmod (...) ---
+def chown_chmod ( fspath, uid=None, gid=None, mode=None, pretend=False ):
+   """Calls chmod(fspath) and chown(fspath) after creating an intermediate
+   ChownChmod instance.
 
-def chown_chmod_recursive (
-   root, uid=None, gid=None, mode=None, pretend=False
-):
-   return ChownChmod (
-      uid, gid, mode, pretend ).chown_chmod_recursive ( root )
-# --- end of chown_chmod_recursive (...) ---
+   arguments:
+   * fspath  --
+   * uid     --
+   * gid     --
+   * mode    --
+   * pretend --
+   """
+   return ChownChmod ( uid, gid, mode, pretend ).chown_chmod ( fspath )
+# --- end of chown_chmod (...) ---
 
 
-class AbstractFsOperations ( object ):
+class AbstractFsOperations ( roverlay.util.objects.AbstractObject ):
+   """Base object for performing filesystem operations."""
 
-   PRETEND = None
+   @abc.abstractproperty
+   def PRETEND ( self ):
+      """A bool that indicates whether fs operations should be fully virtual
+      (print what would be done) or not.
+      Needs to be set by derived classes (as class-wide attribute).
+      """
+      return None
 
    def __init__ ( self,
       stdout=None, stderr=None, uid=None, gid=None,
       file_mode=None, dir_mode=None
    ):
+      """AbstractFsOperations constructor.
+
+      arguments:
+      * stdout    -- stdout stream. Defaults to sys.stdout
+      * stderr    -- stderr stream. Defaults to sys.stderr
+      * uid       -- uid for chown(). Defaults to None (keep uid).
+      * gid       -- gid for chown(). Defaults to None (keep gid).
+      * file_mode -- mode for chmod(<file>). Defaults to None (don't change
+                     mode). Can also be an ls-like str, e.g. "rwxr-x---".
+      * dir_mode  -- mode for chmod(<file>). Defaults to None.
+      """
       if self.__class__.PRETEND is None:
          raise AssertionError ( "derived classes have to set PRETEND." )
 
@@ -400,23 +629,42 @@ class AbstractFsOperations ( object ):
 
       self.info  = self._stdout.write
       self.error = self._stderr.write
-
-      self._setup()
    # --- end of __init__ (...) ---
 
-   def _setup ( self ):
-      pass
-   # --- end of _setup (...) ---
-
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def _dodir ( self, dirpath, mkdir_p ):
-      pass
+      """Ensures that a directory exists, by creating it if necessary.
+      Also creates parent directories if mkdir_p evaluates to True.
+
+      Returns: success (True/False)
 
-   @roverlay.util.objects.abstractmethod
+      arguments:
+      * dirpath
+      * mkdir_p
+      """
+      return
+
+   @abc.abstractmethod
    def do_touch ( self, fspath ):
-      pass
+      """Similar to "touch <fspath>".
+
+      Returns: success (True/False)
+
+      Raises: IOError, OSError
+      """
+      return
 
    def chown ( self, fspath ):
+      """Calls chown_dir(fspath) or chown_file(fspath), depending on whether
+      fspath is a directory or not.
+
+      Returns: success (passed from chown_dir()/chown_file())
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
       if os.path.isdir ( fspath ):
          return self.chown_dir ( fspath )
       else:
@@ -424,21 +672,60 @@ class AbstractFsOperations ( object ):
    # --- end of chown (...) ---
 
    def chown_stat ( self, fspath, mode ):
+      """Similar to chown(fspath), but checks the given mode in order to
+      decide whether fspath is a dir.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      * mode   -- stat mode
+      """
       if stat.S_ISDIR ( mode ):
          return self.chown_dir ( fspath )
       else:
          return self.chown_file ( fspath )
    # --- end of chown_stat (...) ---
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def chown_dir ( self, fspath ):
-      pass
+      """Changes the owner of a directory.
+
+      Returns: success (True/False)
 
-   @roverlay.util.objects.abstractmethod
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
+      return
+
+   @abc.abstractmethod
    def chown_file ( self, fspath ):
-      pass
+      """Changes the owner of a file.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
+      return
 
    def chmod ( self, fspath ):
+      """Calls chmod_dir(fspath) or chmod_file(fspath), depending on whether
+      fspath is a directory or not.
+
+      Returns: success (passed from chmod_dir()/chmod_file())
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
       if os.path.isdir ( fspath ):
          return self.chmod_dir ( fspath )
       else:
@@ -446,25 +733,59 @@ class AbstractFsOperations ( object ):
    # --- end of chmod (...) ---
 
    def chmod_stat ( self, fspath, mode ):
+      """Similar to chmod(fspath), but checks the given mode in order to
+      decide whether fspath is a dir.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      * mode   -- stat mode
+      """
       if stat.S_ISDIR ( mode ):
          return self.chmod_dir ( fspath )
       else:
          return self.chmod_file ( fspath )
    # --- end of chmod_stat (...) ---
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def chmod_dir ( self, fspath ):
-      pass
+      """Changes the mode of a directory.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
+      return
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def chmod_file ( self, fspath ):
-      pass
+      """Changes the mode of a file.
 
-   def chmod_chown ( self, fspath ):
-      self.chmod ( fspath )
-      self.chown ( fspath )
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
+      return
 
    def chmod_chown ( self, fspath ):
+      """Performs both chmod(fspath) and chown(fspath).
+
+      Returns: 2-tuple ( chmod_success, chown_success )
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      """
       if os.path.isdir ( fspath ):
          return (
             self.chmod_dir ( fspath ), self.chown_dir ( fspath )
@@ -476,6 +797,17 @@ class AbstractFsOperations ( object ):
    # --- end of chmod (...) ---
 
    def chmod_chown_stat ( self, fspath, mode ):
+      """Similar to chmod_chown(), but checks mode in order to decide whether
+      fspath is a dir.
+
+      Returns: 2-tuple ( chmod_success, chown_success )
+
+      Raises: OSError
+
+      arguments:
+      * fspath --
+      * mode   -- stat mode
+      """
       if stat.S_ISDIR ( mode ):
          return (
             self.chmod_dir ( fspath ), self.chown_dir ( fspath )
@@ -486,16 +818,37 @@ class AbstractFsOperations ( object ):
          )
    # --- end of chmod_stat (...) ---
 
-   @roverlay.util.objects.abstractmethod
-   def chmod_chown_recursive ( self, root ):
-      pass
-
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def _copy_file ( self, source, dest ):
-      pass
+      """Copies a file from source to dest.
+
+      Returns: success (True/False)
+
+      Raises: undefined, IOError/OSError are likely
+
+      arguments:
+      * source --
+      * dest   --
+      """
+      return
    # --- end of _copy_file (...) ---
 
    def copy_file ( self, source, dest, chown=True, chmod=True ):
+      """Copies a file from source to dest and calls chmod(),chown()
+      afterwards.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * source --
+      * dest   --
+      * chown  -- bool that controls whether chown() should be called.
+                  Defaults to True.
+      * chmod  -- bool that controls whether chmod() should be called.
+                  Defaults to True.
+      """
       if self._copy_file ( source, dest ):
          if chmod:
             self.chmod_file ( dest )
@@ -508,6 +861,23 @@ class AbstractFsOperations ( object ):
    # --- end of copy_file (...) ---
 
    def dodir ( self, dirpath, mkdir_p=True, chown=True, chmod=True ):
+      """Ensures that a directory exists by creating it if necessary.
+      Also calls chmod(), chown() afterwards.
+
+      Returns: success (True/False)
+
+      Raises: OSError
+
+      arguments:
+      * dirpath --
+      * mkdir_p -- whether to create parent directories as well (if necessary)
+                   Defaults to True.
+      * chown   -- bool that controls whether chown() should be called.
+                   Defaults to True.
+      * chmod   -- bool that controls whether chmod() should be called.
+                   Defaults to True.
+      """
+
       if self._dodir ( dirpath, mkdir_p=mkdir_p ):
          if chmod:
             self.chmod_dir ( dirpath )
@@ -520,30 +890,80 @@ class AbstractFsOperations ( object ):
    # --- end of dodir (...) ---
 
    def dodirs ( self, *dirs, **kwargs ):
+      """Calls dodir(dir) for each dir in dirs.
+
+      arguments:
+      * *dirs    --
+      * **kwargs -- keyword arguments for dodir()
+      """
       for dirpath in dirs:
          self.dodir ( dirpath, **kwargs )
    # --- end of dodirs (...) ---
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def rmdir ( self, dirpath ):
-      pass
+      """Removes an empty directory.
+
+      Returns: success (True/False)
+
+      arguments:
+      * dirpath --
+      """
+      return
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def unlink ( self, fspath ):
-      pass
+      """Removes a file (or link).
+
+      Returns: success (True/False)
+
+      arguments:
+      * fspath --
+      """
+      return
 
    def wipe ( self, fspath ):
+      """Removes fspath if it is an empty directory or a file (or link).
+
+      Returns: success (True/False)
+
+      arguments:
+      * fspath --
+      """
       return self.rmdir ( fspath ) or self.unlink ( fspath )
 
-   @roverlay.util.objects.abstractmethod
+   @abc.abstractmethod
    def symlink ( self, source, link_name ):
-      pass
+      """Creates a symlink.
+
+      Returns: success (True/False)
+
+      arguments:
+      * source    --
+      * link_name --
+      """
+      return
 
    def check_writable ( self,
       fspath, mkdir_chown=False, mkdir_chmod=False, mkdir_p=True
    ):
       """Checks whether fspath can be written. This creates all necessary
-      directories."""
+      directories and creates fspath as empty file.
+
+      Returns: success (True/False)
+
+      Raises: passes IOError,OSError unless its error code is related to
+              missing write permissions
+
+      arguments:
+      * fspath      --
+      * mkdir_chown -- bool that controls whether created directories should
+                       be chown()-ed. Defaults to False.
+      * mkdir_chmod -- bool that controls whether created directories should
+                       be chmod()-ed. Defaults to False.
+      * mkdir_p     -- whether dodir() should create parent dirs as well.
+                       Defaults to True.
+      """
       success = False
 
       ERRNOS_IGNORE = { errno.EACCES, }
@@ -595,6 +1015,21 @@ class AbstractFsOperations ( object ):
    def copy_tree ( self,
       source_root, dest_root, overwrite=True, followlinks=False
    ):
+      """Recursively copies files from source_root to dest_root (while keeping
+      its directory structure). Ownership and permissions are not preserved,
+      instead copied files and created dirs will have to permissions set
+      during initialization of this object.
+
+      Returns: None (implicit)
+
+      arguments:
+      * source_root -- directory from which files should be copied
+      * dest_root   -- directory to which files should be copied
+      * overwrite   -- whether to overwrite files that already exist in
+                       dest_root. Defaults to True(!).
+      * followlinks -- whether to follow symbolic links in os.walk().
+                       Defaults to False.
+      """
       dodir     = self.dodir
       copy_file = self.copy_file
 
@@ -629,6 +1064,18 @@ class AbstractFsOperations ( object ):
    def copy_dirlink_tree ( self,
       source_root, dest_root, overwrite=False, followlinks=False
    ):
+      """Creates symlinks to source_root's content in dest_root.
+
+      Returns: None (implicit)
+
+      arguments:
+      * source_root --
+      * dest_root   --
+      * overwrite   --
+      * followlinks --
+      """
+
+      unlink  = self.unlink
       symlink = self.symlink
 
       source, dest, relpath, dirs, files, dirnames = next (
@@ -641,6 +1088,8 @@ class AbstractFsOperations ( object ):
          for ( my_source, my_source_stat ), ( my_dest, my_dest_stat ) in (
             itertools.chain ( dirs, files )
          ):
+            if my_dest_stat is not None:
+               unlink ( my_dest )
             symlink ( my_source, my_dest )
       else:
          for ( my_source, my_source_stat ), ( my_dest, my_dest_stat ) in (
@@ -653,7 +1102,17 @@ class AbstractFsOperations ( object ):
    def copy_filelink_tree ( self,
       source_root, dest_root, overwrite=False, followlinks=False
    ):
-      dodir = self.dodir
+      """Like copy_tree(), but creates symlinks to files in source_root
+      instead of copying them.
+
+      arguments:
+      * source_root --
+      * dest_root   --
+      * overwrite   --
+      * followlinks --
+      """
+      dodir   = self.dodir
+      unlink  = self.unlink
       symlink = self.symlink
 
       if overwrite:
@@ -667,6 +1126,8 @@ class AbstractFsOperations ( object ):
                if followlinks and stat.S_ISLINK ( source_stat ):
                   dodir ( dest_file )
                else:
+                  if dest_stat is not None:
+                     unlink ( dest_file )
                   symlink ( source_file, dest_file )
       else:
          for source, dest, relpath, dirs, files, dirnames in (
@@ -684,19 +1145,27 @@ class AbstractFsOperations ( object ):
                      symlink ( source_file, dest_file )
    # --- end of copy_filelink_tree (...) ---
 
-
 # --- end of AbstractFsOperations ---
 
+
 class FsOperations ( AbstractFsOperations ):
 
    PRETEND = False
 
-   def _setup ( self ):
+   # this is necessary because the abstract are overridden during __init__()
+   # (which doesn't get recognized by @abc.abstractmethod)
+   chmod_file = None
+   chown_file = None
+   chmod_dir  = None
+   chown_dir  = None
+
+   def __init__ ( self, *args, **kwargs ):
+      super ( FsOperations, self ).__init__ ( *args, **kwargs )
       self.chmod_file = self.perm_env_file.chmod
       self.chown_file = self.perm_env_file.chown
       self.chmod_dir  = self.perm_env_dir.chmod
       self.chown_dir  = self.perm_env_dir.chown
-   # --- end of _setup (...) ---
+   # --- end of __init__ (...) ---
 
    def _copy_file ( self, source, dest ):
       shutil.copyfile ( source, dest )
@@ -709,11 +1178,6 @@ class FsOperations ( AbstractFsOperations ):
       )
    # --- end of _dodir (...) ---
 
-   def chmod_chown_recursive ( self, root ):
-      raise Exception("broken.")
-      for ret in self.perm_env.chown_chmod_recursive ( root ):
-         pass
-
    def rmdir ( self, dirpath ):
       try:
          os.rmdir ( dirpath )
@@ -767,27 +1231,25 @@ class VirtualFsOperations ( AbstractFsOperations ):
       ret = self.perm_env_file.chown ( fspath )
       if ret is not None:
          self.info ( ret + "\n" )
+      return True
 
    def chown_dir ( self, fspath ):
       ret = self.perm_env_dir.chown ( fspath )
       if ret is not None:
          self.info ( ret + "\n" )
+      return True
 
    def chmod_file ( self, fspath ):
       ret = self.perm_env_file.chmod ( fspath )
       if ret is not None:
          self.info ( ret + "\n" )
+      return True
 
    def chmod_dir ( self, fspath ):
       ret = self.perm_env_dir.chmod ( fspath )
       if ret is not None:
          self.info ( ret + "\n" )
-
-   def chmod_chown_recursive ( self, root ):
-      raise Exception("BROKEN.")
-      for word in self.perm_env.chown_chmod_recursive ( root ):
-         if word is not None:
-            self.info ( word + "\n" )
+      return True
 
    def unlink ( self, fspath ):
       self.info ( "rm {!r}\n".format ( fspath ) )


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

commit:     ff58bf49699682c31786b05072e7fe65bb3bb50e
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 19 14:59:23 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 19 14:59:23 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ff58bf49

fsutil: accept file_key function

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

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index b8a69ab..7fede96 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -44,12 +44,14 @@ def walk_up ( dirpath, topdown=False, max_iter=None ):
 def get_fs_dict (
    initial_root, create_item=None, dict_cls=dict,
    dirname_filter=None, filename_filter=None,
-   include_root=False, prune_empty=False,
+   include_root=False, prune_empty=False, file_key=None,
 ):
    # http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
    fsdict         = dict_cls()
    my_root        = os.path.abspath ( initial_root )
 
+   get_file_key   = ( lambda x: x ) if file_key is None else file_key
+
    dictpath_begin = (
       1 + ( my_root.rfind ( os.sep ) if include_root else len ( my_root ) )
    )
@@ -69,11 +71,13 @@ def get_fs_dict (
             parent   = functools.reduce ( dict_cls.get, dictpath[:-1], fsdict )
 
             if create_item is None:
-               parent [dictpath[-1]] = dict_cls.fromkeys ( filenames )
+               parent [dictpath[-1]] = dict_cls.fromkeys (
+                  map ( get_file_key, filenames )
+               )
             else:
                parent [dictpath[-1]] = dict_cls (
                   (
-                     fname,
+                     get_file_key ( fname ),
                      create_item ( ( root + os.sep + fname ), fname, root )
                   )
                   for fname in filenames


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

commit:     43c0ad633946458d8d185e8a456a6379e55dbb82
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 17 16:40:32 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 17 16:40:32 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=43c0ad63

argparser: subparse_parsed()

---
 roverlay/argparser.py | 18 +++++++++++++++++-
 roverlay/argutil.py   |  4 ++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 81b3300..04feff8 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -123,6 +123,17 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
    def parse ( self, *args, **kwargs ):
       self.parse_args ( *args, **kwargs )
       parsed          = vars ( self.parsed )
+      return self.parse_parsed ( parsed )
+   # --- end of parse (...) ---
+
+   def subparse_parsed ( self, parsed ):
+      self.parsed = parsed
+      if hasattr ( self.__class__, 'PARSE_TARGETS' ):
+         for attr in self.__class__.PARSE_TARGETS:
+            getattr ( self, 'parse_' + attr )()
+   # --- end of subparse_parsed (...) ---
+
+   def parse_parsed ( self, parsed ):
       self.parsed     = parsed
       self.extra_conf = dict()
 
@@ -189,7 +200,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
       if hasattr ( self.__class__, 'PARSE_TARGETS' ):
          for attr in self.__class__.PARSE_TARGETS:
             getattr ( self, 'parse_' + attr )()
-   # --- end of parse (...) ---
+   # --- end of parse_parsed (...) ---
 
    def setup ( self ):
       if hasattr ( self.__class__, 'SETUP_TARGETS' ):
@@ -651,6 +662,11 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
 
    def parse_actions ( self ):
       self.command = self.parsed ['command']
+
+      if self.__class__.COMMAND_SUBPARSERS:
+         subparser = self.get_subparser ( self.command )
+         if hasattr ( subparser, 'subparse_parsed' ):
+            subparser.subparse_parsed ( self.parsed )
    # --- end of parse_actions (...) ---
 
 # --- end of RoverlayArgumentParser ---

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 7c36980..b8f8363 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -314,7 +314,7 @@ class ArgumentParserProxy ( object ):
          if default is argparse.SUPPRESS:
             default_str = self.STR_SUPPRESS
 
-         elif default in { True, False }:
+         elif default is True or default is False:
             if flags & self.ARG_INVERSE:
                default_str = self.STR_FALSE if default else self.STR_TRUE
             else:
@@ -392,7 +392,7 @@ class ArgumentParserProxy ( object ):
    # --- end of parse_args (...) ---
 
    def parse ( self, *args, **kwargs ):
-      print ( "ArgumentParserProxy.parse() is deprecated. Use parse_args()." )
+      # likely overridden by derived classes
       return self.parse_args ( *args, **kwargs )
    # --- end of parse (...) ---
 


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

commit:     f2caad3d9b949a0a0ca52219d467fbdc8c75499d
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 17 15:26:08 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 17 15:26:08 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f2caad3d

argparser,argutil: support subparsers

---
 roverlay/argparser.py | 54 +++++++++++++++++++++++++++++++++++-----------
 roverlay/argutil.py   | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 100 insertions(+), 14 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 5b28d0f..d52a1e2 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -6,6 +6,7 @@
 
 import argparse
 import collections
+import sys
 
 import roverlay.core
 import roverlay.argutil
@@ -566,6 +567,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
 class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
 
    MULTIPLE_COMMANDS   = False
+   COMMAND_SUBPARSERS  = None
    COMMAND_DESCRIPTION = None
    DEFAULT_COMMAND     = None
 
@@ -582,6 +584,18 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
          assert self.default_command in self.COMMAND_DESCRIPTION
    # --- end of __init__ (...) ---
 
+   def get_args_to_parse ( self ):
+      if self.__class__.COMMAND_SUBPARSERS is None:
+         return sys.argv[1:]
+      else:
+         args = sys.argv[1:]
+
+         if any ( command in args for command in self.COMMAND_DESCRIPTION ):
+            return args
+         else:
+            return args + [ self.default_command ]
+   # --- end of get_args_to_parse (...) ---
+
    def get_commands ( self ):
       if self.MULTIPLE_COMMANDS:
          return self.command
@@ -590,23 +604,39 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
    # --- end of get_commands (...) ---
 
    def setup_actions ( self ):
-      arg = self.add_argument_group (
-         "actions", title="actions",
-         description=self.format_command_map ( self.COMMAND_DESCRIPTION ),
-      )
+      if self.__class__.COMMAND_SUBPARSERS is None:
+         arg = self.add_argument_group (
+            "actions", title="actions",
+            description=self.format_command_map ( self.COMMAND_DESCRIPTION ),
+         )
 
-      arg (
-         'command', default=self.default_command, metavar='<action>',
-         nargs=( "*" if self.MULTIPLE_COMMANDS else "?" ),
-         choices=self.COMMAND_DESCRIPTION.keys(),
-         flags=self.ARG_HELP_DEFAULT,
-         help="action to perform"
-      )
+         arg (
+            'command', default=self.default_command, metavar='<action>',
+            nargs=( "*" if self.MULTIPLE_COMMANDS else "?" ),
+            choices=self.COMMAND_DESCRIPTION.keys(),
+            flags=self.ARG_HELP_DEFAULT,
+            help="action to perform"
+         )
 
-      return arg
+         return arg
+      else:
+         self.add_subparsers (
+            title="commands",
+            description=self.format_command_map ( self.COMMAND_DESCRIPTION ),
+            dest="command",
+            help="action to perform [%(default)s]",
+         )
+         # set_defaults() not necessary due to get_args_to_parse()
+         self.parser.set_defaults ( command=self.default_command )
+
+         for command in self.COMMAND_DESCRIPTION:
+            subparser = self.add_subparser ( command )
+
+         return None
    # --- end of setup_actions (...) ---
 
    def parse_actions ( self ):
+      print ( self.parsed )
       self.command = self.parsed ['command']
    # --- end of parse_actions (...) ---
 

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index c3981e5..7c36980 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -8,6 +8,7 @@ import os
 import argparse
 import pwd
 import grp
+import sys
 
 
 from roverlay.config.entryutil import deref_entry_safe
@@ -158,6 +159,9 @@ class ArgumentParserError ( Exception ):
 class ArgumentGroupExists ( ArgumentParserError ):
    pass
 
+class SubparserExists ( ArgumentParserError ):
+   pass
+
 class ArgumentFlagException ( ArgumentParserError ):
    pass
 
@@ -207,10 +211,54 @@ class ArgumentParserProxy ( object ):
          self.defaults = dict ( defaults )
 
       self._argument_groups = dict()
+      self._subparsers      = dict()
+      self._subparser_ctrl  = None
 
       self.parsed = None
    # --- end of __init__ (...) ---
 
+   def add_subparsers ( self, ignore_exist=False, **kwargs ):
+      if self._subparser_ctrl is None:
+         self._subparser_ctrl = self.parser.add_subparsers ( **kwargs )
+      elif not ignore_exist:
+         raise AssertionError ( "add_subparsers() already called!" )
+
+      return self._subparser_ctrl
+   # --- end of add_subparsers (...) ---
+
+   def add_subparser ( self,
+      command, defaults=True, proxy_cls=None, **parser_kwargs
+   ):
+      if command in self._subparsers:
+         raise SubparserExists ( command )
+      else:
+         if proxy_cls is None:
+            get_proxy = ArgumentParserProxy.wrap
+         elif proxy_cls is True:
+            get_proxy = self.__class__.wrap
+         elif hasattr ( proxy_cls, 'wrap' ):
+            get_proxy = proxy_cls.wrap
+         else:
+            get_proxy = proxy_cls
+
+         parser = (
+            self.add_subparsers ( ignore_exist=True ).add_parser (
+               command, **parser_kwargs
+            )
+         )
+
+         proxy = get_proxy (
+            parser,
+            defaults = ( self.defaults if defaults is True else defaults )
+         )
+         self._subparsers [command] = proxy
+         return proxy
+   # --- end of add_subparser (...) ---
+
+   def get_subparser ( self, name ):
+      return self._subparsers [name]
+   # --- end of get_subparser (...) ---
+
    def get_options ( self ):
       return self.parsed
    # --- end of get_options (...) ---
@@ -331,12 +379,20 @@ class ArgumentParserProxy ( object ):
       )
    # --- end of group_arg (...) ---
 
-   def parse_args ( self, *args, **kwargs ):
-      self.parsed = self.parser.parse_args ( *args, **kwargs )
+   def get_args_to_parse ( self ):
+      return sys.argv[1:]
+   # --- end of get_args_to_parse (...) ---
+
+   def parse_args ( self, args=None, namespace=None ):
+      self.parsed = self.parser.parse_args (
+         args      = ( self.get_args_to_parse() if args is None else args ),
+         namespace = namespace,
+      )
       return self.parsed
    # --- end of parse_args (...) ---
 
    def parse ( self, *args, **kwargs ):
+      print ( "ArgumentParserProxy.parse() is deprecated. Use parse_args()." )
       return self.parse_args ( *args, **kwargs )
    # --- end of parse (...) ---
 


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

commit:     653293a8f68cff4c4c4ec24dd416877e2eec1f6a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 17 15:50:43 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 17 15:59:14 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=653293a8

argparser: setup subparsers

---
 roverlay/argparser.py | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 5a59dd5..81b3300 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -631,12 +631,18 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
          # (required for proper help=...%(default)s, though)
          #self.parser.set_defaults ( command=self.default_command )
 
-         subparsers = [
-            self.add_subparser ( command )
-               for command in self.COMMAND_DESCRIPTION
-         ]
-         return subparsers
+         subparsers = []
+
+         for command in self.COMMAND_DESCRIPTION:
+            subparser = self.add_subparser (
+               command, proxy_cls=self.__class__.COMMAND_SUBPARSERS[command]
+            )
+            if hasattr ( subparser, 'setup' ):
+               subparser.setup()
+            subparsers.append ( subparser )
+         # -- end if
 
+         return subparsers
       else:
          raise AssertionError (
             "multiple commands with subparsers is not supported."
@@ -644,7 +650,6 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
    # --- end of setup_actions (...) ---
 
    def parse_actions ( self ):
-      print ( self.parsed )
       self.command = self.parsed ['command']
    # --- end of parse_actions (...) ---
 


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

commit:     121aa5600cb23ef787fe0ede4d360158bbed8b52
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 17 15:40:14 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 17 15:40:14 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=121aa560

argparser: forbid "multiple commands + subparsers"

---
 roverlay/argparser.py | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index d52a1e2..5a59dd5 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -619,7 +619,8 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
          )
 
          return arg
-      else:
+
+      elif not self.MULTIPLE_COMMANDS:
          self.add_subparsers (
             title="commands",
             description=self.format_command_map ( self.COMMAND_DESCRIPTION ),
@@ -627,12 +628,19 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
             help="action to perform [%(default)s]",
          )
          # set_defaults() not necessary due to get_args_to_parse()
-         self.parser.set_defaults ( command=self.default_command )
+         # (required for proper help=...%(default)s, though)
+         #self.parser.set_defaults ( command=self.default_command )
 
-         for command in self.COMMAND_DESCRIPTION:
-            subparser = self.add_subparser ( command )
+         subparsers = [
+            self.add_subparser ( command )
+               for command in self.COMMAND_DESCRIPTION
+         ]
+         return subparsers
 
-         return None
+      else:
+         raise AssertionError (
+            "multiple commands with subparsers is not supported."
+         )
    # --- end of setup_actions (...) ---
 
    def parse_actions ( self ):


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

commit:     d741cd6327b979d68dcdedba7d051f1faebc19d2
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Sep 16 10:29:08 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Sep 16 10:29:08 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d741cd63

roverlay/core, locate_config_file(): prefer .local

if not installed:
 (try to) use R-overlay.conf.local as default config file
 and fall back to R-overlay.conf

---
 roverlay/core.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/roverlay/core.py b/roverlay/core.py
index 2872c48..1a5ac5c 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -148,6 +148,9 @@ def locate_config_file (
          if os.path.isfile ( cfg ):
             return cfg
 
+   elif os.path.exists ( CONFIG_FILE_NAME + '.local' ):
+      return CONFIG_FILE_NAME + '.local'
+
    elif os.path.exists ( CONFIG_FILE_NAME ):
       return CONFIG_FILE_NAME
 


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

commit:     817a11df3094d960dea9b1b46b17fcdd9e803be5
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 13 14:58:35 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 13 14:58:35 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=817a11df

fsutil: walk_up()

Generator that walks a filesystem path upwards, e.g.
"/a/b/c/d" -> [ "/a/b/c/d", "/a/b/c", "/a/b", "/a" ]

---
 roverlay/fsutil.py | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index 515f214..7f3296a 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -18,6 +18,27 @@ _OS_CHOWN = getattr ( os, 'lchown', os.chown )
 _OS_CHMOD = getattr ( os, 'lchmod', os.chmod )
 
 
+def walk_up ( dirpath, topdown=False, max_iter=None ):
+   path_elements = os.path.normpath ( dirpath ).split ( os.sep )
+
+   if path_elements:
+      p_start = 0 if path_elements[0] else 1
+
+      if max_iter is None:
+         high = len ( path_elements )
+      else:
+         high = min ( max_iter + p_start, len ( path_elements ) )
+
+
+      if topdown:
+         for k in range ( p_start+1, high+1 ):
+            yield os.sep.join ( path_elements[:k] )
+      else:
+         for k in range ( high, p_start, -1 ):
+            yield os.sep.join ( path_elements[:k] )
+
+# --- end of walk_up (...) ---
+
 def get_fs_dict (
    initial_root, create_item=None, dict_cls=dict,
    dirname_filter=None, filename_filter=None,


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

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

roverlay/fsutil: get fs dict from os.walk()

---
 roverlay/fsutil.py | 53 ++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 11 deletions(-)

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index 5efac20..515f214 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -5,6 +5,7 @@
 # either version 2 of the License, or (at your option) any later version.
 
 import errno
+import functools
 import os
 import pwd
 import stat
@@ -17,17 +18,47 @@ _OS_CHOWN = getattr ( os, 'lchown', os.chown )
 _OS_CHMOD = getattr ( os, 'lchmod', os.chmod )
 
 
-def readlink_f ( fspath ):
-   try:
-      f = os.readlink ( fspath )
-   except OSError as oserr:
-      if oserr.errno in { errno.ENOENT, errno.EINVAL }:
-         f = fspath
-      else:
-         raise
-
-   return os.path.abspath ( f )
-# --- end of readlink_f (...) ---
+def get_fs_dict (
+   initial_root, create_item=None, dict_cls=dict,
+   dirname_filter=None, filename_filter=None,
+   include_root=False, prune_empty=False,
+):
+   # http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
+   fsdict         = dict_cls()
+   my_root        = os.path.abspath ( initial_root )
+
+   dictpath_begin = (
+      1 + ( my_root.rfind ( os.sep ) if include_root else len ( my_root ) )
+   )
+
+   for root, dirnames, filenames in os.walk ( initial_root ):
+      if dirname_filter:
+         dirnames[:] = [ d for d in dirnames if dirname_filter ( d ) ]
+
+      if filename_filter:
+         filenames[:] = [ f for f in filenames if filename_filter ( f ) ]
+
+      if not prune_empty or filenames or dirnames:
+         dict_relpath = root[dictpath_begin:]
+
+         if dict_relpath:
+            dictpath = dict_relpath.split ( os.sep )
+            parent   = functools.reduce ( dict_cls.get, dictpath[:-1], fsdict )
+
+            if create_item is None:
+               parent [dictpath[-1]] = dict_cls.fromkeys ( filenames )
+            else:
+               parent [dictpath[-1]] = dict_cls (
+                  (
+                     fname,
+                     create_item ( ( root + os.sep + fname ), fname, root )
+                  )
+                  for fname in filenames
+               )
+   # -- end for
+
+   return fsdict
+# --- end of get_fs_dict (...) ---
 
 def create_subdir_check ( parent, fs_sep=os.sep ):
    PARENT_PATH = parent.rstrip ( fs_sep ).split ( fs_sep )


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

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

roverlay/argutil, dirstr(): return abspath

---
 roverlay/argutil.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 198ccda..90444a3 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -120,7 +120,7 @@ def dirstr ( value ):
       if value[0] == '~':
          return value.rstrip ( os.path.sep )
       else:
-         return os.path.sep + value.strip ( os.path.sep )
+         return os.path.abspath ( value )
    else:
       raise argparse.ArgumentTypeError (
          "cannot create dir-string for {!r}".format ( value )


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

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

roverlay/argparser: --usage action

---
 roverlay/argparser.py | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 1304874..561951e 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -23,6 +23,17 @@ from roverlay.argutil import \
    ArgumentParserProxy
 
 
+
+class UsageAction ( argparse.Action ):
+
+   def __call__ ( self, parser, namespace, values, option_string=None ):
+      parser.print_usage()
+      parser.exit()
+   # --- end of __call__ (...) ---
+
+# --- end of UsageAction ---
+
+
 class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
 
    DESCRIPTION_TEMPLATE = None
@@ -192,8 +203,16 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
          '-V', '--version', action='version',
          version=self.defaults.get ( "version", roverlay.core.version )
       )
+      return self
    # --- end of setup_version (...) ---
 
+   def setup_usage ( self ):
+      self.arg (
+         '--usage', action=UsageAction, help="print usage", nargs=0,
+      )
+      return self
+   # --- end of setup_usage (...) ---
+
    def setup_config_minimal ( self ):
       config_arg = self.add_argument_group (
          'config', title='config file options'


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

commit:     95937f273a0c6cb15e0c9cc0bd33731cf62444db
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Sep 11 10:40:48 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Sep 11 10:40:48 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=95937f27

runtime: create private _info, _error functions

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

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index 3e251b9..5ef540d 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -284,8 +284,10 @@ class IndependentRuntimeEnvironment ( MinimalRuntimeEnvironment ):
 
       self.stdout   = stdout if stdout is not None else sys.stdout
       self.stderr   = stderr if stderr is not None else sys.stderr
-      self.info     = self.stdout.write
-      self.error    = self.stderr.write
+      self._info    = self.stdout.write
+      self._error   = self.stderr.write
+      self.info     = self._info
+      self.error    = self._error
 
       if installed:
          self.INSTALLINFO = self.access_constant ( 'INSTALLINFO' )


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

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

remove setupdirs command from roverlay.py

It's now part of the roverlay setup script.

---
 roverlay/argparser.py     | 25 ++------------------
 roverlay/defaultscript.py | 60 +----------------------------------------------
 2 files changed, 3 insertions(+), 82 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index a08cf00..1304874 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -684,7 +684,7 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParser ):
 
    SETUP_TARGETS = (
       'version', 'actions', 'config', 'overlay', 'remote',
-      'overlay_creation', 'setupdirs', 'additional_actions', 'misc',
+      'overlay_creation', 'additional_actions', 'misc',
    )
    PARSE_TARGETS = ( 'actions', 'config', )
 
@@ -704,7 +704,6 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParser ):
          'apply_rules',
          'apply package rules verbosely and exit afterwards'
       ),
-      ( 'setupdirs', 'create configured directories etc.' ),
       ( 'distmap_rebuild', 'regenerate distmap' ),
    ))
 
@@ -716,7 +715,7 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParser ):
       if command == 'nop':
          roverlay.core.die ( "Nothing to do!", roverlay.core.DIE.NOP )
 
-      elif command in { 'setupdirs', 'distmap_rebuild' }:
+      elif command in { 'distmap_rebuild', }:
          self.parsed ['want_logging']   = False
          self.parsed ['load_main_only'] = True
 
@@ -735,26 +734,6 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParser ):
       self.command = command
    # --- end of parse_actions (...) ---
 
-   def setup_setupdirs ( self ):
-      arg = self.add_argument_group (
-         'setupdirs', title='setupdirs options',
-      )
-
-      arg (
-         '--target-uid', dest='target_uid', default=os.getuid(),
-         metavar='<uid>', type=is_uid, flags=self.ARG_WITH_DEFAULT,
-         help='uid of the user that will run roverlay',
-      )
-      arg (
-         '--target-gid', dest='target_gid', default=os.getgid(),
-         metavar='<gid>', type=is_gid, flags=self.ARG_WITH_DEFAULT,
-         help='gid of the user that will run roverlay',
-      )
-
-
-      return arg
-   # --- end of setup_setupdirs (...) ---
-
    def setup_additional_actions ( self ):
       arg = self.add_argument_group (
          "additional_actions", title='additional actions',

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 5f47e39..ad87520 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -40,10 +40,7 @@ def main ( installed, *args, **kw ):
    main_env = roverlay.runtime.RuntimeEnvironment ( installed, *args, **kw )
    main_env.setup()
 
-   if main_env.want_command ( 'setupdirs' ):
-      sys.exit ( run_setupdirs ( main_env ) )
-
-   elif run_early_commands ( main_env ):
+   if run_early_commands ( main_env ):
       sys.exit ( os.EX_OK )
 
    elif (
@@ -145,61 +142,6 @@ def run_early_commands ( env ):
 # --- end of run_early_commands (...) ---
 
 
-def run_setupdirs ( env ):
-   config     = env.config
-   target_uid = env.options ['target_uid']
-   target_gid = env.options ['target_gid' ]
-
-   dodir            = roverlay.util.dodir
-   find_config_path = roverlay.config.entryutil.find_config_path
-
-   dirmode_private  = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP
-   #clear_mode = ~(stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
-   #get_mode = lambda old, want_mode: ( old & clear_mode ) | want_mode
-
-   WANT_USERDIR = roverlay.config.entrymap.WANT_USERDIR
-   WANT_PRIVATE = roverlay.config.entrymap.WANT_PRIVATE
-   WANT_FILEDIR = roverlay.config.entrymap.WANT_FILEDIR
-
-   listlike    = lambda a: hasattr(a, '__iter__') and not isinstance(a, str)
-   iter_values = lambda b: () if b is None else (b if listlike(b) else ( b, ))
-
-   my_uid = os.getuid()
-   my_gid = os.getgid()
-   should_chown = my_uid != target_uid or my_gid != target_gid
-
-   # it's not necessary to create all of the listed dirs because some of
-   # them are automatically created at runtime, but doing so results in
-   # a (mostly) complete filesystem layout
-   #
-   for config_key, entry in roverlay.config.entrymap.CONFIG_ENTRY_MAP.items():
-      if isinstance ( entry, dict ) and 'want_dir_create' in entry:
-         for value in iter_values (
-            config.get ( find_config_path ( config_key ), None )
-         ):
-            dirmask = entry ['want_dir_create']
-            dirpath = (
-               os.path.dirname ( value.rstrip ( os.sep ) )
-               if dirmask & WANT_FILEDIR else value.rstrip ( os.sep )
-            )
-
-            if dirpath:
-               if os.path.islink ( dirpath ):
-                  sys.stdout.write (
-                     '{!r} is a symlink - skipping setupdir '
-                     'actions.\n'.format ( dirpath )
-                  )
-               else:
-                  #elif dodir ( dirpath ):
-                  dodir ( dirpath )
-                  if dirmask & WANT_PRIVATE:
-                     os.chmod ( dirpath, dirmode_private )
-                  if dirmask & WANT_USERDIR and should_chown:
-                     os.chown ( dirpath, target_uid, target_gid )
-
-   return os.EX_OK
-# --- end of run_setupdirs (...) ---
-
 def run_distmap_rebuild ( env ):
    if env.action_done ( 'distmap_rebuild' ):
       return os.EX_OK


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

commit:     371a3c585e51383a05df6986f0c6b02631147cc7
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 10 14:33:09 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 10 14:40:01 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=371a3c58

roverlay: setupscript.py

This file provides various env objects and a main() function for setting up
roverlay.

It is meant to replace:
* the roverlay-mkconfig command (now "roverlay-setup mkconfig")
* most of the ebuild's pkg_config() and roverlay's setupdirs command
  (unified in "roverlay-setup init" and more flexible/safer, e.g.
   a has --pretend option that gives detailed information about what
   would be done)

Additionally, it can be used to manage roverlay's hooks (besides setting up the
default hooks; TODO).

TODO notes:
* needs a cleanup
* only "--import-config symlink=root" is implemented, currently
* isn't able to handle not-installed versions of roverlay
* the replaced commands/functionality has to be removed

---
 roverlay/setupscript.py | 1035 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1035 insertions(+)

diff --git a/roverlay/setupscript.py b/roverlay/setupscript.py
new file mode 100644
index 0000000..2a23103
--- /dev/null
+++ b/roverlay/setupscript.py
@@ -0,0 +1,1035 @@
+# R overlay -- setup script
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+
+import argparse
+import collections
+import errno
+import logging
+import os
+import shutil
+import stat
+import sys
+import textwrap
+
+import roverlay.argutil
+import roverlay.argparser
+import roverlay.fsutil
+import roverlay.runtime
+
+import roverlay.config.defconfig
+import roverlay.config.entrymap
+import roverlay.config.entryutil
+
+import roverlay.static.hookinfo
+
+import roverlay.util.counter
+
+if sys.hexversion >= 0x3000000:
+   read_user_input = input
+else:
+   read_user_input = raw_input
+
+
+
+
+
+
+def arg_stdout_or_fs ( value ):
+   if value == '-':
+      return value
+   else:
+      return os.path.abspath ( os.path.expanduser ( value ) )
+# --- end of arg_stdout_or_fs (...) ---
+
+
+
+
+class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
+   MULTIPLE_COMMANDS = False
+   COMMAND_DESCRIPTION = {
+      'init':     'initialize roverlay\'s config and filesystem layout',
+      'mkconfig': 'generate a config file',
+   }
+   DEFAULT_COMMAND = "init"
+
+   COMMANDS_WITH_PRETEND = frozenset ({ 'init', })
+
+   SETUP_TARGETS = ( 'version', 'actions', 'setup', 'config', 'init', )
+   PARSE_TARGETS = ( 'actions', 'setup', 'init', )
+
+
+   def setup_setup ( self ):
+      arg = self.setup_setup_minimal ( title='common options' )
+
+      arg (
+         '--output', '-O', metavar="<file|dir|->", dest='output',
+         default='-', type=arg_stdout_or_fs,
+         flags=self.ARG_WITH_DEFAULT,
+         help='output file/dir/stream used by various commands (\'-\' for stdout)',
+      )
+
+      arg (
+         '--pretend', '-p', dest='pretend',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help='show what would be done',
+      )
+
+      arg (
+         '--ask', '-a', dest='wait_confirm',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help='get confirmation before actually doing anything',
+      )
+
+      return arg
+   # --- end of setup_setup (...) ---
+
+   def parse_setup ( self ):
+      self.parse_setup_minimal()
+
+      if self.parsed ['pretend']:
+         for cmd in self.get_commands():
+            if cmd not in self.__class__.COMMANDS_WITH_PRETEND:
+               self.parser.exit (
+                  "{!r} command does not support --pretend.".format ( cmd )
+               )
+   # --- end of parse_setup (...) ---
+
+   def setup_config ( self ):
+      arg = self.add_argument_group (
+         "config", title="options for the main config file"
+      )
+
+      arg (
+         '--expand-user', dest='config_expand_user',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help="expand \'~\' to the target user\'s home directory",
+      )
+
+      arg (
+         '--variable', '-v', metavar="<key=\"value\">", dest='config_vars',
+         default=[], action='append',
+         type=roverlay.argutil.is_config_opt,
+         help="additional variables",
+      )
+
+      return arg
+   # --- end of setup_config (...) ---
+
+   def setup_init ( self ):
+      arg = self.add_argument_group (
+         'init', title='options for the \'init\' command'
+      )
+
+      arg (
+         '--enable-default-hooks', dest='want_default_hooks',
+         default=True,
+         flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+         help='enable/update the default hooks',
+      )
+
+      arg (
+         '--no-default-hooks', dest='want_default_hooks',
+         flags=self.ARG_SHARED|self.ARG_OPT_OUT,
+         help='disable the default hooks',
+      )
+
+      arg (
+         '--import-config', '-I', dest='import_config',
+         default="symlink",
+         choices=[
+            "disable",
+            "symlink", "symlink=root",
+            "symlink=dirs", "symlink=files",
+            "copy"
+         ],
+         metavar='<mode>',
+         flags=self.ARG_WITH_DEFAULT,
+         help=(
+            'choose whether and how --conf-root should be imported: '
+             '%(choices)s'
+         ),
+      )
+
+      arg (
+         '--no-import-config', dest='import_config',
+         action='store_const', const='disable',
+         help='disable config import (same as \'--import-config disable\')',
+      )
+
+
+      arg (
+         '--target-uid', dest='target_uid', default=os.getuid(),
+         metavar='<uid>', type=roverlay.argutil.is_uid,
+         flags=self.ARG_WITH_DEFAULT,
+         help="uid of the user that will run roverlay",
+      )
+
+      arg (
+         '--target-gid', dest='target_gid', default=os.getgid(),
+         metavar='<gid>', type=roverlay.argutil.is_gid,
+         flags=self.ARG_WITH_DEFAULT,
+         help='gid of the user that will run roverlay',
+      )
+
+   # --- end of setup_init (...) ---
+
+   def parse_init ( self ):
+      my_uid = os.getuid()
+
+      if my_uid and self.parsed ['target_uid'] != my_uid:
+         if self.parsed ['pretend']:
+            sys.stderr.write (
+               "!!! --target-uid: users cannot configure other users.\n\n"
+            )
+         else:
+            self.parser.exit (
+               "--target-uid: users cannot configure other users."
+            )
+   # --- end of parse_init (...) ---
+
+
+# --- end of SetupArgParser ---
+
+
+class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
+
+   LOG_LEVEL         = logging.INFO
+
+   SHARED_DIR_MODE   = roverlay.fsutil.get_stat_mode ( "rwxrwxr-x" )
+   PRIVATE_DIR_MODE  = roverlay.fsutil.get_stat_mode ( "rwxr-x---" )
+   SHARED_FILE_MODE  = roverlay.fsutil.get_stat_mode ( "rw-rw-r--" )
+   PRIVATE_FILE_MODE = roverlay.fsutil.get_stat_mode ( "rw-r-----" )
+
+   def __init__ ( self, *args, **kwargs ):
+      super ( SetupEnvironment, self ).__init__ ( *args, **kwargs )
+
+      self.UID             = os.getuid()
+      self.GID             = os.getgid()
+
+      self.expanduser      = None
+      self.fs_ops          = None
+      self.fs_ops_virtual  = None
+
+      self.want_chown      = None
+      self.data_root       = None
+      self.work_root       = None
+      self.conf_root       = None
+      self.user_conf_root  = None
+   # --- end of __init__ (...) ---
+
+   def create_argparser ( self ):
+      instinfo = self.access_constant ( 'INSTALLINFO' )
+
+      return SetupArgParser (
+         description = 'roverlay setup script',
+         defaults    = {
+            'work_root'         : instinfo ['workroot'],
+            'data_root'         : instinfo ['libexec'],
+            'conf_root'         : instinfo ['confroot'],
+            'private_conf_root' : instinfo ['workroot'] + os.sep + 'config',
+            'import_config'     : 'symlink=root',
+         },
+      )
+   # --- end of create_argparser (...) ---
+
+   def _get_config_roots ( self ):
+      return (
+         os.path.realpath ( self.conf_root ),
+         os.path.realpath ( self.user_conf_root )
+      )
+   # --- end of get_config_roots (...) ---
+
+   def get_user_config_root ( self ):
+      conf_root, user_conf_root = self._get_config_roots()
+      if conf_root == user_conf_root:
+         return None
+      else:
+         return user_conf_root
+   # --- end of get_user_config_root (...) ---
+
+   def get_config_file_path ( self ):
+      return (
+         self.work_root + os.sep + self.access_constant ( 'config_file_name' )
+      )
+   # --- end of get_config_file_path (...) ---
+
+   def create_new_target_config ( self ):
+      return self.create_new_config (
+         config_str=self.create_config_file ( expand_user=True )
+      )
+   # --- end of create_new_target_config (...) ---
+
+   def _expanduser_pwd ( self, fspath ):
+      return roverlay.fsutil.pwd_expanduser (
+         fspath, self.options ['target_uid']
+      )
+   # --- end of _expanduser_pwd (...) ---
+
+   def create_config_file ( self, expand_user=False ):
+      conf_creator = roverlay.config.defconfig.RoverlayConfigCreation (
+         work_root = (
+            self.work_root if expand_user else self.options ['work_root']
+         ),
+         data_root = (
+            self.data_root if expand_user else self.options ['data_root']
+         ),
+         conf_root = (
+            self.user_conf_root if expand_user
+            else self.options ['private_conf_root']
+         ),
+      )
+
+      for kv in self.options ['config_vars']:
+         key, sepa, value = kv.partition ( '=' )
+         if not sepa:
+            raise Exception ( "bad variable given: {!r}".format ( kv ) )
+         else:
+            conf_creator.set_option ( key, value )
+
+      return conf_creator.get_str()
+   # --- end of create_config_file (...) ---
+
+   def write_config_file ( self, output=None, expand_user=None ):
+      config_file_str = self.create_config_file (
+         expand_user = (
+            self.options ['config_expand_user'] if expand_user is None
+            else expand_user
+         ),
+      )
+      if not output or output == '-':
+         self.info ( config_file_str )
+      else:
+         with open ( output, 'wt' ) as FH:
+            FH.write ( config_file_str )
+   # --- end of write_config_file (...) ---
+
+   def auto_reconfigure ( self ):
+      self.reconfigure ( self.create_config_file() )
+   # --- end of auto_reconfigure (...) ---
+
+   def setup ( self ):
+      self.PWD_INITIAL = os.getcwd()
+      self.setup_common()
+
+      # ref
+      options = self.options
+
+      target_uid = options ['target_uid']
+      target_gid = options ['target_gid']
+
+      self.want_chown = ( target_uid != self.UID or target_gid != self.GID )
+
+      if self.UID == target_uid:
+         expanduser      = os.path.expanduser
+         self.expanduser = os.path.expanduser
+      else:
+         expanduser      = self._expanduser_pwd
+         self.expanduser = self._expanduser_pwd
+
+      self.work_root      = expanduser ( options ['work_root'] )
+      self.data_root      = expanduser ( options ['data_root'] )
+      self.conf_root      = expanduser ( options ['conf_root'] )
+      self.user_conf_root = expanduser ( options ['private_conf_root'] )
+
+
+      self.fs_ops_virtual = {
+         'private_dir': roverlay.fsutil.VirtualFsOperations (
+            uid=target_uid, gid=target_gid, mode=self.PRIVATE_DIR_MODE,
+         ),
+         'shared_dir': roverlay.fsutil.VirtualFsOperations (
+            uid=target_uid, gid=target_gid, mode=self.SHARED_DIR_MODE,
+         ),
+         'private_file': roverlay.fsutil.VirtualFsOperations (
+            uid=target_uid, gid=target_gid, mode=self.PRIVATE_FILE_MODE,
+         ),
+         'shared_file': roverlay.fsutil.VirtualFsOperations (
+            uid=target_uid, gid=target_gid, mode=self.SHARED_FILE_MODE,
+         ),
+      }
+
+      if options ['pretend']:
+         self.fs_ops = self.fs_ops_virtual
+      else:
+         self.fs_ops =  {
+            'private_dir': roverlay.fsutil.FsOperations (
+               uid=target_uid, gid=target_gid, mode=self.PRIVATE_DIR_MODE,
+            ),
+            'shared_dir': roverlay.fsutil.FsOperations (
+               uid=target_uid, gid=target_gid, mode=self.SHARED_DIR_MODE,
+            ),
+            'private_file': roverlay.fsutil.FsOperations (
+               uid=target_uid, gid=target_gid, mode=self.PRIVATE_FILE_MODE,
+            ),
+            'shared_file': roverlay.fsutil.FsOperations (
+               uid=target_uid, gid=target_gid, mode=self.SHARED_FILE_MODE,
+            ),
+         }
+
+      # bind fs_ops
+      self.private_dir  = self.fs_ops ['private_dir']
+      self.shared_dir   = self.fs_ops ['shared_dir']
+      self.private_file = self.fs_ops ['private_file']
+      self.shared_file  = self.fs_ops ['shared_file']
+   # --- end of setup (...) ---
+
+   def wait_confirm ( self,
+      message=None, message_inline=None,
+      prepend_newline=True, append_newline=True
+   ):
+      try:
+         if prepend_newline:
+            self.info ( '\n' )
+
+         if message is not None:
+            self.info ( str ( message ) + '\n' )
+
+         if message_inline:
+            self.info (
+               "Press Enter to continue ({!s}) ... ".format ( message_inline )
+            )
+         else:
+            self.info ( "Press Enter to continue ... " )
+
+         self.stdout.flush()
+
+         ret = read_user_input().strip()
+
+      except ( KeyboardInterrupt, EOFError ):
+         self.info ( "\n" )
+         sys.exit ( 130 )
+      else:
+         if append_newline:
+            self.info ( '\n' )
+
+         return ret
+   # --- end of wait_confirm (...) ---
+
+   def wait_confirm_can_skip ( self,
+      SKIP_WORDS=frozenset({ 'skip', 'no', 'n'}), **kwargs
+   ):
+      assert 'message_inline' not in kwargs
+
+      if self.options ['wait_confirm']:
+
+         user_reply = self.wait_confirm (
+            message_inline="type {} to skip this step".format (
+               '/'.join ( repr( word ) for word in sorted( SKIP_WORDS ) )
+            ),
+            **kwargs
+         )
+
+         return user_reply.lower() not in SKIP_WORDS
+      else:
+         return True
+   # --- end of wait_confirm (...) ---
+
+   def get_init_env ( self ):
+      return SetupInitEnvironment ( self )
+   # --- end of get_init_env (...) ---
+
+   def get_hook_env ( self ):
+      return SetupHookEnvironment ( self )
+   # --- end of get_hook_env (...) ---
+
+# --- end of SetupEnvironment ---
+
+
+class SetupSubEnvironment ( object ):
+
+   NEEDS_CONFIG_TREE = False
+
+   ACTIONS = None
+
+   def __init__ ( self, setup_env ):
+      super ( SetupSubEnvironment, self ).__init__()
+
+      self.setup_env = setup_env
+      self.stdout    = setup_env.stdout
+      self.stderr    = setup_env.stderr
+      self.info      = setup_env.info
+      self.error     = setup_env.error
+
+      if self.NEEDS_CONFIG_TREE:
+         self.config = self.setup_env.create_new_target_config()
+      else:
+         self.config = None
+
+      self.setup()
+   # --- end of __init__ (...) ---
+
+   def setup ( self ):
+      pass
+   # --- end of setup (...) ---
+
+   def run ( self, steps_to_skip=None, verbose_skip=True, steps=None ):
+      pretend = self.setup_env.options ['pretend']
+      ACTIONS = steps if steps is not None else self.ACTIONS
+
+      if ACTIONS:
+         if steps_to_skip:
+            methods_to_call = [
+               (
+                  None if item[0] in steps_to_skip
+                  else getattr ( self, 'do_' + item[0] )
+               ) for item in ACTIONS
+            ]
+         else:
+            methods_to_call = [
+               getattr ( self, 'do_' + item[0] ) for item in ACTIONS
+            ]
+
+         wait_confirm_can_skip = self.setup_env.wait_confirm_can_skip
+
+
+         for method, action in zip ( methods_to_call, ACTIONS ):
+            if method is None:
+               if verbose_skip:
+                  self.info ( "{}: skipped.\n".format ( action[0] ) )
+
+            elif not action[1]:
+               method ( pretend=pretend )
+
+            elif wait_confirm_can_skip (
+               message=method.__doc__, append_newline=False
+            ):
+               method ( pretend=pretend )
+            else:
+               self.info ( "skipped.\n" )
+
+      else:
+         raise NotImplementedError (
+            "{}.{}()".format ( self.__class__.__name__, "do_all" )
+         )
+   # --- end of run (...) ---
+
+
+# --- end of SetupSubEnvironment ---
+
+
+class SetupInitEnvironment ( SetupSubEnvironment ):
+
+   ACTIONS = (
+      ( 'pretend', False ),
+      ( 'prepare_config_file', False ),
+      ( 'import_config', True ),
+      ( 'setupdirs', True ),
+      ( 'write_config_file', True ),
+      ( 'enable_default_hooks', True ),
+   )
+
+   NEEDS_CONFIG_TREE = True
+
+   def setup ( self ):
+      self.config_file_str = None
+   # --- end of setup (...) ---
+
+   IMPORT_CONFIG_DESC = {
+      'disable'       : False,
+      'symlink'       : 'symlink {conf_root} to {user_conf_root}',
+      'symlink=root'  : 'symlink {conf_root} to {user_conf_root}',
+      'symlink=dirs'  : (
+         'symlink files/dirs from {conf_root} to {user_conf_root}/'
+      ),
+      'symlink=files' : (
+         'recursively copy {conf_root} to {user_conf_root}, '
+         'but symlink files instead of copying them'
+      ),
+      'copy'          : 'recursively copy {conf_root} to {user_conf_root}',
+   }
+
+   def gen_pretend_options ( self ):
+      options = self.setup_env.options
+
+      def get_option ( key ):
+         val = options [key]
+         if isinstance ( val, str ):
+            return val
+         elif hasattr ( val, '__iter__' ):
+            return ' '.join ( str(x) for x in val )
+         elif isinstance ( val, bool ):
+            return "yes" if val else "no"
+         elif val is None:
+            return "<undef>"
+         else:
+            return str ( val )
+      # --- end of get_option (...) ---
+
+      comment_path    = lambda a, b: a if a == b else ( a + ' (' + b + ')' )
+      get_path_option = lambda k, b: comment_path ( get_option ( k ), b )
+
+      fmt_vars = {
+         'conf_root'     : options ['conf_root'],
+         'user_conf_root': options ['private_conf_root']
+      }
+
+      yield ( "user/uid",  get_option ( 'target_uid' ) )
+      yield ( "group/gid", get_option ( 'target_gid' ) )
+
+      yield ( "work root",
+         get_path_option ( 'work_root', self.setup_env.work_root )
+      )
+      yield ( "data root",
+         get_path_option ( 'data_root', self.setup_env.data_root )
+      )
+      yield ( "roverlay\'s config root",
+         get_path_option ( 'conf_root', self.setup_env.conf_root )
+      )
+      yield ( "user\'s config root",
+         get_path_option ( 'private_conf_root', self.setup_env.user_conf_root )
+      )
+
+      import_config = get_option ( 'import_config' )
+      if import_config == 'disable':
+         yield ( "import config", "no" )
+      else:
+         yield ( "import config",
+            "yes, "
+            + self.IMPORT_CONFIG_DESC [import_config].format ( **fmt_vars )
+         )
+
+      yield ( "enable default hooks", get_option ( 'want_default_hooks' ) )
+      yield ( "additional config variables", get_option ( 'config_vars' ) )
+   # --- end of gen_pretend_options (...) ---
+
+   def gen_pretend_lines ( self, append_newline=True ):
+      options  = list ( self.gen_pretend_options() )
+      COLUMNS  = os.environ.get ( 'COLUMNS', 78 )
+      desc_len = min ( COLUMNS // 2,
+         1 + max ( len(desc) for desc, value in options )
+      )
+
+      line_wrapper = textwrap.TextWrapper (
+         width=COLUMNS, initial_indent='',
+         subsequent_indent=( (desc_len+5) * ' ' ),
+         break_long_words=False, break_on_hyphens=False,
+      )
+
+
+      yield 'Configuration:'
+      for desc, value in options:
+         yield line_wrapper.fill (
+            "- {desc:<{l}}: {value}".format (
+               desc=desc, l=desc_len, value=value,
+            )
+         )
+
+      if append_newline:
+         yield ""
+   # --- end of gen_pretend_lines (...) ---
+
+   def do_pretend ( self, pretend ):
+      """Shows what would be done."""
+      self.info ( '\n'.join ( self.gen_pretend_lines() ) + '\n' )
+   # --- end of do_pretend (...) ---
+
+   def do_prepare_config_file ( self, pretend ):
+      """Creates the config file (in memory)."""
+      self.config_file_str = self.setup_env.create_config_file (
+         expand_user=self.setup_env.options ['config_expand_user']
+      )
+   # --- end of do_prepare_config_file (...) ---
+
+   def do_import_config ( self, pretend ):
+      """Imports the config."""
+      mode           = self.setup_env.options ['import_config']
+      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 )
+
+      if user_conf_root is None and (
+         fs_ops.unlink ( self.setup_env.user_conf_root )
+      ):
+         # config_root was a symlink
+
+         if pretend:
+            user_conf_root = self.setup_env.user_conf_root
+         else:
+            user_conf_root = self.setup_env.get_user_config_root()
+
+      # -- end if
+
+
+      if user_conf_root is None:
+         self.info (
+            "user has no private config directory - skipping config import.\n"
+         )
+
+      elif mode in { 'symlink=root', 'symlink' }:
+         if not fs_ops.wipe ( user_conf_root ):
+            self.setup_env.die (
+               "failed to remove {!r}.\n".format ( user_conf_root )
+            )
+         elif not fs_ops.symlink ( self.setup_env.conf_root, user_conf_root ):
+            self.setup_env.die (
+               "could not create symlink to {!r}.".format (
+                  self.setup_env.conf_root
+               )
+            )
+
+
+         pass
+      else:
+         raise NotImplementedError ( mode )
+   # --- end of do_import_config (...) ---
+
+   def do_setupdirs ( self, pretend ):
+      """Creates directories with proper permissions."""
+      create_subdir_check = roverlay.fsutil.create_subdir_check
+      config              = self.config
+      find_config_path    = roverlay.config.entryutil.find_config_path
+      dodir_private       = self.setup_env.private_dir.dodir
+      dodir_shared        = self.setup_env.shared_dir.dodir
+
+
+      WANT_USERDIR = roverlay.config.entrymap.WANT_USERDIR
+      WANT_PRIVATE = roverlay.config.entrymap.WANT_PRIVATE
+      WANT_FILEDIR = roverlay.config.entrymap.WANT_FILEDIR
+
+      listlike    = lambda a: (
+         hasattr(a, '__iter__') and not isinstance(a, str)
+      )
+      iter_values = lambda b: (
+         () if b is None else (b if listlike(b) else ( b, ))
+      )
+
+      dirs_exclude = [
+         create_subdir_check ( self.setup_env.conf_root ),
+         create_subdir_check ( self.setup_env.data_root ),
+      ]
+      if self.setup_env.get_user_config_root() is None:
+         dirs_exclude.append (
+            create_subdir_check ( self.setup_env.user_conf_root )
+         )
+      else:
+         print ( self.setup_env.get_user_config_root() )
+
+      # don't print exclude/skip messages more than once per dir
+      dirs_already_excluded = set()
+
+      private_dirs       = set()
+      private_dirs_chown = set()
+      shared_dirs        = set()
+      shared_dirs_chown  = set()
+
+      # it's not necessary to create all of the listed dirs because some of
+      # them are automatically created at runtime, but doing so results in
+      # a (mostly) complete filesystem layout
+      #
+      for config_key, entry in (
+         roverlay.config.entrymap.CONFIG_ENTRY_MAP.items()
+      ):
+         if isinstance ( entry, dict ) and 'want_dir_create' in entry:
+            for value in iter_values (
+               config.get ( find_config_path ( config_key ), None )
+            ):
+               dirmask = entry ['want_dir_create']
+               dirpath = (
+                  os.path.dirname ( value.rstrip ( os.sep ) )
+                  if dirmask & WANT_FILEDIR else value.rstrip ( os.sep )
+               )
+
+               if not dirpath or dirpath in dirs_already_excluded:
+                  pass
+
+               elif any ( ex ( dirpath ) for ex in dirs_exclude ):
+                  self.info (
+                     "setupdirs: excluding {!r}\n".format ( dirpath )
+                  )
+                  dirs_already_excluded.add ( dirpath )
+
+               elif os.path.islink ( dirpath ):
+                  self.info (
+                     '{!r} is a symlink - skipping setupdir '
+                     'actions.\n'.format ( dirpath )
+                  )
+                  dirs_already_excluded.add ( dirpath )
+
+               elif dirmask & WANT_USERDIR:
+                  if dirmask & WANT_PRIVATE:
+                     private_dirs_chown.add ( dirpath )
+                  else:
+                     shared_dirs_chown.add ( dirpath )
+
+               elif dirmask & WANT_PRIVATE:
+                  private_dirs.add ( dirpath )
+
+               else:
+                  shared_dirs.add ( dirpath )
+      # -- end for
+
+
+      private_dirs      -= private_dirs_chown
+      shared_dirs_chown -= private_dirs
+      shared_dirs       -= shared_dirs_chown
+
+      for dirpath in shared_dirs:
+         dodir_shared ( dirpath, chown=False )
+
+      for dirpath in shared_dirs_chown:
+         dodir_shared ( dirpath, chown=True )
+
+      for dirpath in private_dirs:
+         dodir_private ( dirpath, chown=False )
+
+      for dirpath in private_dirs_chown:
+         dodir_private ( dirpath, chown=True )
+
+      self.setup_env.private_dir.chmod_chown ( self.setup_env.work_root )
+   # --- end of do_setupdirs (...) ---
+
+   def do_write_config_file ( self, pretend ):
+      """Writes the config file to disk."""
+      cfile = self.setup_env.get_config_file_path()
+      if not self.config_file_str:
+         self.setup_env.die ( "no config file created!" )
+      elif pretend:
+         self.info ( "Would write config file to {!r}.\n".format ( cfile ) )
+      else:
+         with open ( cfile, 'wt' ) as FH:
+            FH.write ( self.config_file_str )
+
+      self.setup_env.private_file.chmod_chown ( cfile )
+   # --- end of do_write_config_file (...) ---
+
+   def do_enable_default_hooks ( self, pretend ):
+      """Enables the default hooks, e.g. git history creation."""
+      hook_env = self.setup_env.get_hook_env()
+      if not hook_env.enable_defaults():
+         die ( "failed to enable hooks." )
+   # --- end of do_enable_default_hooks (...) ---
+
+# --- end of SetupInitEnvironment ---
+
+
+class HookScript ( object ):
+
+   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]
+      else:
+         self.default_events = False
+         self.priority       = None
+         self.is_hidden      = False
+   # --- end of __init__ (...) ---
+
+   def is_visible ( self ):
+      return not self.is_hidden and (
+         self.priority is None or self.priority >= 0
+      )
+   # --- end of is_visible (...) ---
+
+   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=(
+            "auto" if self.priority is None else
+               ( "IGNORE" if self.priority < 0 else self.priority )
+         ),
+      )
+   # --- end of __str__ (...) ---
+
+   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 (...) ---
+
+
+# --- end of HookScript ---
+
+
+class HookScriptDir ( object ):
+
+   def __init__ ( self, root ):
+      super ( HookScriptDir, self ).__init__()
+
+      self.root      = root
+      self._scripts  = collections.OrderedDict()
+   # --- end of __init__ (...) ---
+
+   def __bool__ ( self ):
+      return bool ( self._scripts )
+   # --- end of __bool__ (...) ---
+
+   def get_script ( self, 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():
+         if script.is_visible():
+            yield script
+   # --- end of iter_scripts (...) ---
+
+   def scan ( self ):
+      root = self.root
+      try:
+         filenames = sorted ( os.listdir ( root ) )
+      except OSError as oserr:
+         if oserr.errno != errno.ENOENT:
+            raise
+
+      else:
+         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
+   # --- end of scan (...) ---
+
+# --- end of HookScriptDir ---
+
+
+class SetupHookEnvironment ( 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'
+         )
+      else:
+         self.user_hook_root = None
+         self.writable       = 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 )
+   # --- end of setup (...) ---
+
+   def _link_hook ( self, source, link ):
+      if os.path.lexists ( link ):
+         linkdest = os.path.realpath ( link )
+
+         message = 'Skipping activation of hook {!r} - '.format ( link )
+
+         if linkdest == source or linkdest == os.path.realpath ( source ):
+            self.info ( message + "already set up.\n" )
+            return True
+
+         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" )
+
+         return None
+      else:
+         return self.setup_env.private_file.symlink ( source, link )
+   # --- end of _link_hook (...) ---
+
+   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
+         self.setup_env.private_dir.dodir ( destdir )
+
+         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:
+               success = False
+      # -- end if
+
+      return success
+   # --- end of link_hooks_v (...) ---
+
+   def enable_defaults ( self ):
+      # not strict: missing hooks are ignored
+      success = False
+      if self.hook_root:
+         success = True
+         default_hooks = self.hook_root.get_default_scripts()
+         for event, hooks in default_hooks.items():
+            if not self.link_hooks_v ( event, hooks ):
+               success = False
+      # -- end if
+
+      return success
+   # --- end of enable_defaults (...) ---
+
+
+# --- end of SetupHookEnvironment ---
+
+
+def setup_main():
+   env = SetupEnvironment()
+   env.setup()
+
+   if env.wants_command ( "mkconfig" ):
+      env.write_config_file ( env.options ['output'] )
+   elif env.wants_command ( "init" ):
+      env.get_init_env().run()
+
+
+# --- end of setup_main (...) ---


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

commit:     bed92a84ba5816f9db6320d335c08db2a47f73e4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 10 14:28:24 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 10 14:29:37 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=bed92a84

fsutil: perform/simulate filesystem operations

rudimentary support for common fs operations.
The VirtualFsOps class can be used to print operations to a stream (stdout).

---
 roverlay/fsutil.py | 416 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 416 insertions(+)

diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
new file mode 100644
index 0000000..5efac20
--- /dev/null
+++ b/roverlay/fsutil.py
@@ -0,0 +1,416 @@
+# R overlay --
+# -*- 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 errno
+import os
+import pwd
+import stat
+import sys
+
+import roverlay.util.common
+import roverlay.util.objects
+
+_OS_CHOWN = getattr ( os, 'lchown', os.chown )
+_OS_CHMOD = getattr ( os, 'lchmod', os.chmod )
+
+
+def readlink_f ( fspath ):
+   try:
+      f = os.readlink ( fspath )
+   except OSError as oserr:
+      if oserr.errno in { errno.ENOENT, errno.EINVAL }:
+         f = fspath
+      else:
+         raise
+
+   return os.path.abspath ( f )
+# --- end of readlink_f (...) ---
+
+def create_subdir_check ( parent, fs_sep=os.sep ):
+   PARENT_PATH = parent.rstrip ( fs_sep ).split ( fs_sep )
+
+   def is_subdir ( dirpath ):
+      return all (
+         this == expect for this, expect in zip (
+            dirpath.rstrip ( fs_sep ).split ( fs_sep ),
+            PARENT_PATH
+         )
+      )
+   # --- end of is_subdir (...) ---
+
+   return is_subdir
+# --- end of create_subdir_check (...) ---
+
+
+def pwd_expanduser ( fspath, uid ):
+   if not fspath or fspath[0] != '~':
+      return fspath
+   elif len ( fspath ) < 2:
+      return pwd.getpwuid ( uid ).pw_dir
+   elif fspath[1] == os.sep:
+      return pwd.getpwuid ( uid ).pw_dir + fspath[1:]
+   else:
+      return fspath
+# --- end of pwd_expanduser (...) ---
+
+def get_bitwise_sum ( iterable, initial_value=None ):
+   ret = initial_value if initial_value is not None else 0
+   for item in iterable:
+      ret |= item
+   return ret
+# --- end of get_bitwise_sum (...) ---
+
+def get_stat_mode ( mode_str ):
+
+   def iter_mode_values ( mode_str ):
+      # rwxrwxrwx
+      # 012345678
+      # r -> pos % 3 == 0
+      # w -> pos % 3 == 1
+      # x -> pos % 3 == 2
+
+
+      # COULDFIX: parse sticky bit etc. (not necessary, currently)
+      if len ( mode_str ) > 9:
+         raise ValueError ( mode_str )
+
+      for pos, char in enumerate ( mode_str ):
+         if char != '-':
+            block  = pos // 3
+            subpos = pos % 3
+            if subpos == 0:
+               # r
+               assert char == 'r'
+               if block == 0:
+                  yield stat.S_IRUSR
+               elif block == 1:
+                  yield stat.S_IRGRP
+               else:
+                  yield stat.S_IROTH
+
+            elif subpos == 1:
+               # w
+               assert char == 'w'
+               if block == 0:
+                  yield stat.S_IWUSR
+               elif block == 1:
+                  yield stat.S_IWGRP
+               else:
+                  yield stat.S_IWOTH
+
+            elif subpos == 2:
+               # x
+               assert char == 'x'
+               if block == 0:
+                  yield stat.S_IXUSR
+               elif block == 1:
+                  yield stat.S_IXGRP
+               else:
+                  yield stat.S_IXOTH
+
+   # --- end of iter_mode_values (...) ---
+
+   return get_bitwise_sum ( iter_mode_values ( mode_str ) )
+# --- end of get_stat_mode (...) ---
+
+class ChownChmod ( object ):
+
+   def __init__ ( self, uid=None, gid=None, mode=None, pretend=False ):
+      super ( ChownChmod, self ).__init__()
+
+      self.pretend  = bool ( pretend )
+      do_chown = uid is not None or gid is not None
+
+      self.uid      = -1 if uid is None else uid
+      self.gid      = -1 if gid is None else gid
+
+      if do_chown:
+         self.chown_str = "chown {uid:d}:{gid:d} {{}}".format (
+            uid=self.uid, gid=self.gid
+         )
+         if self.pretend:
+            self.chown = self.chown_str.format
+         else:
+            self.chown = self._do_chown
+      else:
+         self.chown_str = "NO CHOWN {}"
+         self.chown = self._nullfunc
+
+
+      if mode is None:
+         self.mode = None
+      elif isinstance ( mode, str ):
+         self.mode = get_stat_mode ( mode )
+      else:
+         self.mode = mode
+
+      if self.mode is None:
+         self.chmod_str = "NO CHMOD {}"
+         self.chmod = self._nullfunc
+      else:
+         self.chmod_str ="chmod {mode:o} {{}}".format ( mode=self.mode )
+         if self.pretend:
+            self.chmod = self.chmod_str.format
+         else:
+            self.chmod = self._do_chmod
+   # --- end of __init__ (...) ---
+
+   def _nullfunc ( self, fspath ):
+      return None
+
+   def _do_chown ( self, fspath, _chown=_OS_CHOWN ):
+      _chown ( fspath, self.uid, self.gid )
+      return self.chown_str.format ( fspath )
+
+   def _do_chmod ( self, fspath, _chmod=_OS_CHMOD ):
+      _chmod ( fspath, self.mode )
+      return self.chmod_str.format ( fspath )
+
+   def chown_chmod ( self, fspath ):
+      # should be renamed to chmod_chown()
+      return (
+         self.chmod ( fspath ),
+         self.chown ( fspath )
+      )
+   # --- end of chown_chmod (...) ---
+
+   def chown_chmod_recursive ( self, root ):
+      chown = self.chown
+      chmod = self.chmod
+
+      if os.path.isfile ( root ):
+         yield chmod ( root )
+         yield chown ( root )
+
+      else:
+         for current_root, dirnames, filenames in os.walk ( root ):
+            yield chmod ( current_root )
+            yield chown ( current_root )
+
+            for filename in filenames:
+               fpath = current_root + os.sep + filename
+               yield chmod ( fpath )
+               yield chown ( fpath )
+   # --- end of chown_chmod_recursive (...) ---
+
+# --- end of ChownChmod ---
+
+
+def chown_chmod ( root, uid=None, gid=None, mode=None, pretend=False ):
+   return ChownChmod ( uid, gid, mode, pretend ).chown_chmod ( root )
+# --- end of chown_chmod (...) ---
+
+def chown_chmod_recursive (
+   root, uid=None, gid=None, mode=None, pretend=False
+):
+   return ChownChmod (
+      uid, gid, mode, pretend ).chown_chmod_recursive ( root )
+# --- end of chown_chmod_recursive (...) ---
+
+
+class AbstractFsOperations ( object ):
+
+   PRETEND = None
+
+   def __init__ ( self,
+      stdout=None, stderr=None, uid=None, gid=None, mode=None
+   ):
+      if self.__class__.PRETEND is None:
+         raise AssertionError ( "derived classes have to set PRETEND." )
+
+      super ( AbstractFsOperations, self ).__init__()
+      self.perm_env = ChownChmod (
+         uid=uid, gid=gid, mode=mode, pretend=self.__class__.PRETEND
+      )
+      self._stdout = sys.stdout if stdout is None else stdout
+      self._stderr = sys.stderr if stderr is None else stderr
+
+      self.info  = self._stdout.write
+      self.error = self._stderr.write
+   # --- end of __init__ (...) ---
+
+   @roverlay.util.objects.abstractmethod
+   def _dodir ( self, dirpath, mkdir_p ):
+      pass
+
+   @roverlay.util.objects.abstractmethod
+   def do_touch ( self, fspath ):
+      pass
+
+   @roverlay.util.objects.abstractmethod
+   def chown ( self, fspath ):
+      pass
+
+   @roverlay.util.objects.abstractmethod
+   def chmod ( self, fspath ):
+      pass
+
+   def chmod_chown ( self, fspath ):
+      self.chmod ( fspath )
+      self.chown ( fspath )
+
+   @roverlay.util.objects.abstractmethod
+   def chmod_chown_recursive ( self, root ):
+      pass
+
+   def dodir ( self, dirpath, mkdir_p=True, chown=True, chmod=True ):
+      if self._dodir ( dirpath, mkdir_p=mkdir_p ):
+         if chmod:
+            self.chmod ( dirpath )
+         if chown:
+            self.chown ( dirpath )
+
+         return True
+
+      else:
+         return False
+   # --- end of dodir (...) ---
+
+   def dodirs ( self, *dirs, **kwargs ):
+      for dirpath in dirs:
+         self.dodir ( dirpath, **kwargs )
+   # --- end of dodirs (...) ---
+
+   @roverlay.util.objects.abstractmethod
+   def rmdir ( self, dirpath ):
+      pass
+
+   @roverlay.util.objects.abstractmethod
+   def unlink ( self, fspath ):
+      pass
+
+   def wipe ( self, fspath ):
+      return self.rmdir ( fspath ) or self.unlink ( fspath )
+
+   @roverlay.util.objects.abstractmethod
+   def symlink ( self, source, link_name ):
+      pass
+
+   def check_writable ( self,
+      fspath, mkdir_chown=False, mkdir_chmod=False, mkdir_p=True
+   ):
+      """Checks whether fspath can be written. This creates all necessary
+      directories."""
+      success = False
+
+      try:
+         if self.do_touch ( fspath ):
+            success = True
+
+      except IOError as ioerr:
+         if ioerr.errno == errno.ENOENT:
+            try:
+               if self.dodir (
+                  os.path.dirname ( fspath ),
+                  chown=mkdir_chown, chmod=mkdir_chmod, mkdir_p=mkdir_p
+               ) and self.do_touch ( fspath ):
+                  success = True
+
+            except ( OSError, IOError ) as err:
+               if err.errno != errno.EPERM:
+                  raise
+
+      return success
+   # --- end of check_writable (...) ---
+
+# --- end of AbstractFsOperations ---
+
+class FsOperations ( AbstractFsOperations ):
+
+   PRETEND = False
+
+   def _dodir ( self, dirpath, mkdir_p ):
+      return roverlay.util.common.dodir (
+         dirpath, mkdir_p=mkdir_p, log_exception=False
+      )
+   # --- end of _dodir (...) ---
+
+   def chmod ( self, fspath ):
+      self.perm_env.chmod ( fspath )
+
+   def chown ( self, fspath ):
+      self.perm_env.chown ( fspath )
+
+   def chmod_chown ( self, fspath ):
+      self.perm_env.chown_chmod ( fspath )
+
+   def chmod_chown_recursive ( self, root ):
+      for ret in self.perm_env.chown_chmod_recursive ( root ):
+         pass
+
+   def rmdir ( self, dirpath ):
+      try:
+         os.rmdir ( dirpath )
+      except OSError as oserr:
+         return oserr.errno == errno.ENOENT
+      else:
+         return True
+   # --- end of rmdir (...) ---
+
+   def unlink ( self, fspath ):
+      try:
+         os.unlink ( fspath )
+      except OSError as oserr:
+         return oserr.errno == errno.ENOENT
+      else:
+         return True
+
+   def symlink ( self, source, link_name ):
+      try:
+         os.symlink ( source, link_name )
+      except OSError:
+         return False
+      else:
+         return True
+
+   def do_touch ( self, fspath ):
+      if not os.path.lexists ( fspath ):
+         with open ( fspath, 'a' ) as FH:
+            pass
+      return True
+
+
+class VirtualFsOperations ( AbstractFsOperations ):
+
+   PRETEND = True
+
+   def _dodir ( self, dirpath, mkdir_p ):
+      if mkdir_p:
+         self.info ( "mkdir -p {!s}\n".format ( dirpath ) )
+      else:
+         self.info ( "mkdir {!s}\n".format ( dirpath ) )
+      return True
+
+   def chown ( self, fspath ):
+      ret = self.perm_env.chown ( fspath )
+      if ret is not None:
+         self.info ( ret + "\n" )
+
+   def chmod ( self, fspath ):
+      ret = self.perm_env.chmod ( fspath )
+      if ret is not None:
+         self.info ( ret + "\n" )
+
+   def chmod_chown_recursive ( self, root ):
+      for word in self.perm_env.chmod_chown_recursive ( root ):
+         if word is not None:
+            self.info ( word + "\n" )
+
+   def unlink ( self, fspath ):
+      self.info ( "rm {!r}\n".format ( fspath ) )
+      return True
+
+   def rmdir ( self, dirpath ):
+      self.info ( "rmdir {!r}\n".format ( dirpath ) )
+      return True
+
+   def symlink ( self, source, link_name ):
+      self.info ( "ln -s {} {}\n".format ( source, link_name ) )
+      return True
+
+   def do_touch ( self, fspath ):
+      self.info ( "touch {}\n".format ( fspath ) )
+      return True


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

commit:     bfef26d7cf86185b1d15764e682a221431cce584
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 10 14:27:51 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 10 14:27:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=bfef26d7

misc argparser changes

---
 roverlay/argparser.py | 25 ++++++++++++++++---------
 roverlay/argutil.py   |  6 ++++++
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index c7be8f6..a08cf00 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -18,7 +18,8 @@ from roverlay.argutil import \
    get_gid, is_gid, get_uid, is_uid, \
    is_fs_dir, is_fs_dir_or_void, is_fs_file, \
    is_fs_file_or_dir, is_fs_file_or_void, \
-   is_config_opt, dirstr, dirstr_existing, couldbe_dirstr_existing, \
+   is_config_opt, dirstr, dirstr_existing, \
+   couldbe_dirstr_existing, couldbe_dirstr_existing_or_empty, \
    ArgumentParserProxy
 
 
@@ -497,14 +498,11 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
       return self.setup_misc_minimal()
    # --- end of setup_misc (...) ---
 
-   def setup_setup_minimal ( self ):
-      assert os.sep == "/"
-
-      arg = self.add_argument_group ( 'setup', title='setup options' )
+   def setup_setup_minimal ( self, title='setup options' ):
+      arg = self.add_argument_group ( 'setup', title=title )
 
       arg (
          '--work-root', '-W', dest='work_root',
-         default="~/roverlay",
          flags=self.ARG_WITH_DEFAULT|self.ARG_META_DIR,
          type=couldbe_dirstr_existing,
          help=(
@@ -514,24 +512,33 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
 
       arg (
          '--data-root', '-D', dest='data_root',
-         default="/usr/share/roverlay",
          flags=self.ARG_WITH_DEFAULT|self.ARG_META_DIR,
          type=couldbe_dirstr_existing,
          help='roverlay\'s static data (eclass, hook scripts,...)',
       )
 
       arg (
-         '--conf-root', '-C', dest='conf_root',
-         default="/etc/roverlay",
+         '--conf-root', dest='conf_root',
          flags=self.ARG_WITH_DEFAULT|self.ARG_META_DIR,
          type=couldbe_dirstr_existing,
          help='roverlay\'s config files (dependency rules,...)',
       )
 
+      arg (
+         '--conf-dir', '--my-conf-root', '-C', dest='private_conf_root',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_META_DIR,
+         type=couldbe_dirstr_existing_or_empty,
+         help='private directory for config files (\'\' for --conf-root)',
+      )
 
       return arg
    # --- end of setup_setup_minimal (...) ---
 
+   def parse_setup_minimal ( self ):
+      if not self.parsed.get ( 'private_conf_root', True ):
+         self.parsed ['private_conf_root'] = self.parsed ['conf_root']
+   # --- end of parse_setup_minimal (...) ---
+
 # --- end of RoverlayArgumentParserBase ---
 
 

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index d6ba97e..198ccda 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -146,6 +146,12 @@ def couldbe_dirstr_existing ( value ):
          "{!r} cannot be a directory.".format ( dstr )
       )
 
+def couldbe_dirstr_existing_or_empty ( value ):
+   if not value:
+      return ""
+   else:
+      return couldbe_dirstr_existing ( value )
+
 class ArgumentParserError ( Exception ):
    pass
 


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

commit:     c8c61bed9c1d086cf5675467ae1d1262d0659207
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 10 14:26:52 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 10 14:26:52 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c8c61bed

roverlay/runtime: config access

IndependentRuntimeEnvironment: create new config tree, access constants

---
 roverlay/runtime.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index bbc73d7..3e251b9 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -17,6 +17,9 @@ import roverlay.stats.collector
 import roverlay.util.objects
 import roverlay.recipe.easylogger
 
+import roverlay.config.tree
+import roverlay.config.const
+
 from roverlay.core import DIE, die
 
 # TODO: move/merge roverlay.core.DIE into runtime env
@@ -267,19 +270,55 @@ class RuntimeEnvironment ( RuntimeEnvironmentBase ):
 class IndependentRuntimeEnvironment ( MinimalRuntimeEnvironment ):
 
    LOG_FORMAT = None
+   LOG_LEVEL  = None
 
-   def __init__ ( self, installed=True ):
+   def __init__ ( self, installed=True, stdout=None, stderr=None ):
       super ( IndependentRuntimeEnvironment, self ).__init__()
-      self.config = roverlay.config.tree.ConfigTree ( register_static=False )
 
       self.CONFIG_DEFAULTS = { 'installed': installed, }
-      self.extend_config ( self.CONFIG_DEFAULTS )
 
+      self.config   = self.create_new_config()
       self.parser   = None
       self.options  = None
       self.commands = None
+
+      self.stdout   = stdout if stdout is not None else sys.stdout
+      self.stderr   = stderr if stderr is not None else sys.stderr
+      self.info     = self.stdout.write
+      self.error    = self.stderr.write
+
+      if installed:
+         self.INSTALLINFO = self.access_constant ( 'INSTALLINFO' )
+      else:
+         self.INSTALLINFO = None
    # --- end of __init__ (...) ---
 
+   def create_new_config ( self, config_str=None, apply_defaults=True ):
+      ctree = roverlay.config.tree.ConfigTree ( register_static=False )
+
+      if apply_defaults:
+         ctree.merge_with ( self.CONFIG_DEFAULTS )
+
+      if config_str:
+         ctree.get_loader().parse_config ( config_str )
+
+      return ctree
+   # --- end of create_new_config (...) ---
+
+   def reconfigure ( self, config_str=None ):
+      self.reset_config()
+      if config_str:
+         self.config.get_loader().parse_config ( config_str )
+   # --- end of reconfigure (...) ---
+
+   def access_constant ( self, key ):
+      return roverlay.config.const.lookup ( key )
+   # --- end of access_constant (...) ---
+
+   def wants_command ( self, *commands ):
+      return any ( cmd in self.commands for cmd in commands )
+   # --- end of wants_command (...) ---
+
    def extend_config ( self, additional_config ):
       self.config.merge_with ( additional_config )
    # --- end of extend_config (...) ---
@@ -312,7 +351,10 @@ class IndependentRuntimeEnvironment ( MinimalRuntimeEnvironment ):
 
    def setup_common ( self ):
       roverlay.recipe.easylogger.force_console_logging (
-         log_formatter=logging.Formatter ( self.LOG_FORMAT )
+         log_formatter = logging.Formatter ( self.LOG_FORMAT ),
+         log_level     = (
+            logging.DEBUG if self.LOG_LEVEL is None else self.LOG_LEVEL
+         ),
       )
       self.setup_argparser()
    # --- end of setup_common (...) ---


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

commit:     e89719a69f61008ac51bd8c7b3a3e24b905ea4f3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep  6 17:21:56 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep  6 17:21:56 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=e89719a6

argparser: support >=1 command(s)

+ get_options(), get_commands() functions for getting options/commands

---
 roverlay/argparser.py | 14 ++++++++++++--
 roverlay/argutil.py   | 11 +++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 98b09a1..c7be8f6 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -73,7 +73,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
             # '* <space> <command> - <command description>'
             '* {cmd} - {desc}'.format (
                cmd=cmd.ljust ( 15 ), desc=desc
-            ) for cmd, desc in command_map.items()
+            ) for cmd, desc in command_map.items() if cmd is not None
          )
       )
    # --- end of format_command_map (...) ---
@@ -537,6 +537,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
 
 class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
 
+   MULTIPLE_COMMANDS   = False
    COMMAND_DESCRIPTION = None
    DEFAULT_COMMAND     = None
 
@@ -551,6 +552,13 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
          assert self.default_command in self.COMMAND_DESCRIPTION
    # --- end of __init__ (...) ---
 
+   def get_commands ( self ):
+      if self.MULTIPLE_COMMANDS:
+         return self.command
+      else:
+         return ( self.command, )
+   # --- end of get_commands (...) ---
+
    def setup_actions ( self ):
       arg = self.add_argument_group (
          "actions", title="actions",
@@ -559,7 +567,8 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
 
       arg (
          'command', default=self.default_command, metavar='<action>',
-         nargs="?", choices=self.COMMAND_DESCRIPTION.keys(),
+         nargs=( "*" if self.MULTIPLE_COMMANDS else "?" ),
+         choices=self.COMMAND_DESCRIPTION.keys(),
          flags=self.ARG_HELP_DEFAULT,
          help="action to perform"
       )
@@ -573,6 +582,7 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
 
 # --- end of RoverlayArgumentParser ---
 
+
 class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
 
    DESCRIPTION_TEMPLATE = "roverlay status tool {version}\n{license}"

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 73e88b6..d6ba97e 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -9,6 +9,9 @@ import argparse
 import pwd
 import grp
 
+
+from roverlay.config.entryutil import deref_entry_safe
+
 def get_uid ( user ):
    try:
       return int ( user )
@@ -193,6 +196,14 @@ class ArgumentParserProxy ( object ):
       self.parsed = None
    # --- end of __init__ (...) ---
 
+   def get_options ( self ):
+      return self.parsed
+   # --- end of get_options (...) ---
+
+   def get_commands ( self ):
+      return ()
+   # --- end of get_commands (...) ---
+
    def get_default ( self, key, *args ):
       return self.defaults.get ( key, *args )
    # --- end of get_default (...) ---


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

commit:     fba66f36ad0cad176d7b024880d92d2693058800
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep  6 17:24:28 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep  6 17:24:28 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=fba66f36

roverlay/runtime: IndependentRuntimeEnvironment

env for scripts that are independent of roverlay's core functionality.

This allows to add a setup script that handles config file creation (already
implemented as roverlay-mkconfig), config initialization (fs layout and what's
currently done by pkg_config() in the live ebuild, but more controlled)
and enabling/disabling hooks.

---
 roverlay/runtime.py | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 122 insertions(+), 3 deletions(-)

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index de20f91..bbc73d7 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -14,10 +14,54 @@ import roverlay.core
 import roverlay.hook
 import roverlay.remote.repolist
 import roverlay.stats.collector
+import roverlay.util.objects
+import roverlay.recipe.easylogger
 
 from roverlay.core import DIE, die
 
-class RuntimeEnvironmentBase ( object ):
+# TODO: move/merge roverlay.core.DIE into runtime env
+
+
+class MinimalRuntimeEnvironment ( object ):
+
+   HLINE = 79 * '-'
+
+   def __init__ ( self ):
+      super ( MinimalRuntimeEnvironment, self ).__init__()
+      self.logger = None
+      self.bind_logger ( logging.getLogger() )
+   # -- end of __init__ (...) ---
+
+   def bind_logger ( self, logger ):
+      self.logger       = logger
+      self.log_debug    = logger.debug
+      self.log_info     = logger.info
+      self.log_warn     = logger.warn
+      self.log_warning  = logger.warning
+      self.log_error    = logger.error
+      self.log_critical = logger.critical
+   # --- end of bind_logger (...) ---
+
+   @roverlay.util.objects.abstractmethod
+   def setup ( self ):
+      pass
+
+   def die ( self, msg=None, code=None ):
+      """
+      Calls syst.exit (code:=1) after printing a message (if any).
+      """
+      code = 1 if code is None else code
+      if msg is not None:
+         sys.stderr.write ( msg + "\n" )
+#      else:
+#         sys.stderr.write ( "died.\n" )
+      sys.exit ( code )
+   # --- end of die (...) ---
+
+# --- end of MinimalRuntimeEnvironment ---
+
+
+class RuntimeEnvironmentBase ( MinimalRuntimeEnvironment ):
 
    ARG_PARSER_CLS  = None
    KEEP_ARG_PARSER = False
@@ -28,11 +72,9 @@ class RuntimeEnvironmentBase ( object ):
       config_file_name=roverlay.core.DEFAULT_CONFIG_FILE_NAME
    ):
       super ( RuntimeEnvironmentBase, self ).__init__()
-      self.logger            = logging.getLogger()
       self.installed         = bool ( installed )
       self.hide_exceptions   = bool ( hide_exceptions )
       self.config_file_name  = str ( config_file_name )
-      self.HLINE             = 79 * '-'
 
       self.stats             = roverlay.stats.collector.static
       self.config            = None
@@ -220,3 +262,80 @@ class RuntimeEnvironment ( RuntimeEnvironmentBase ):
    # --- end of optionally (...) ---
 
 # --- end of RuntimeEnvironment ---
+
+
+class IndependentRuntimeEnvironment ( MinimalRuntimeEnvironment ):
+
+   LOG_FORMAT = None
+
+   def __init__ ( self, installed=True ):
+      super ( IndependentRuntimeEnvironment, self ).__init__()
+      self.config = roverlay.config.tree.ConfigTree ( register_static=False )
+
+      self.CONFIG_DEFAULTS = { 'installed': installed, }
+      self.extend_config ( self.CONFIG_DEFAULTS )
+
+      self.parser   = None
+      self.options  = None
+      self.commands = None
+   # --- end of __init__ (...) ---
+
+   def extend_config ( self, additional_config ):
+      self.config.merge_with ( additional_config )
+   # --- end of extend_config (...) ---
+
+   def reset_config ( self ):
+      self.config.reset()
+      self.extend_config ( self.CONFIG_DEFAULTS )
+   # --- end of reset_config (...) ---
+
+   def inject_config_path ( self, path, value ):
+      return self.config.inject ( path, value, suppress_log=True )
+   # --- end of inject_config_path (...) ---
+
+   @roverlay.util.objects.abstractmethod
+   def create_argparser ( self ):
+      pass
+   # --- end of create_argparser (...) ---
+
+   def setup_argparser ( self ):
+      parser = self.create_argparser()
+      if parser is not False:
+         parser.setup()
+         self.parser = parser
+
+         parser.parse()
+
+         self.options  = parser.get_options()
+         self.commands = parser.get_commands()
+   # --- end of do_setup_parser (...) ---
+
+   def setup_common ( self ):
+      roverlay.recipe.easylogger.force_console_logging (
+         log_formatter=logging.Formatter ( self.LOG_FORMAT )
+      )
+      self.setup_argparser()
+   # --- end of setup_common (...) ---
+
+   def setup ( self ):
+      self.setup_common()
+   # --- end of setup (...) ---
+
+   def option ( self, key, fallback=None ):
+      return self.options.get ( key, fallback )
+   # --- end of option (...) ---
+
+   def optionally ( self, func, key, *args, **kwargs ):
+      if self.options.get ( key, False ):
+         return func ( *args, **kwargs )
+      else:
+         return None
+   # --- end of optionally (...) ---
+
+   def is_installed ( self ):
+      return self.config.get_or_fail ( 'installed' )
+   # --- end of is_installed (...) ---
+
+   installed = property ( is_installed )
+
+# --- end of IndependentRuntimeEnvironment ---


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

commit:     1777b3476fa5ccd8c97d74f79b178debf0bb5ad7
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep  3 15:43:29 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep  3 15:43:29 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1777b347

packageinfo, parse_ebuild_distfiles(): accept kwargs

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

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index af44450..fb7b996 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -740,9 +740,9 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
       )
    # --- end of parse_ebuild_src_uri (...) ---
 
-   def parse_ebuild_distfiles ( self, category_name ):
+   def parse_ebuild_distfiles ( self, category_name, **kw ):
       parser = self.parse_ebuild_src_uri ( category_name )
-      for distfile in parser.iter_local_files():
+      for distfile in parser.iter_local_files ( **kw ):
          yield distfile
    # --- end of parse_ebuild_distfiles (...) ---
 


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

commit:     0f45bb772f6f80766f54f6e18ac3fbef9b7b20d3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Sep  2 12:25:29 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Sep  2 12:25:29 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0f45bb77

fix --sync-imports

---
 roverlay/argparser.py     | 2 +-
 roverlay/defaultscript.py | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index def3076..e1ded67 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -415,7 +415,7 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
       arg = self.setup_remote_minimal()
 
       arg (
-         '--sync-imports', dest='sync_imports',
+         '--sync-imports', dest='sync_imported', default=argparse.SUPPRESS,
          flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
          help=(
             'allow fetching of source files for imported ebuilds even if '

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 6e2443c..5f47e39 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -266,6 +266,8 @@ def run_overlay_create ( env ):
       ebuild_import_nosync = env.option ( 'sync_imported' )
       if ebuild_import_nosync is None:
          ebuild_import_nosync = env.config.get_or_fail ( 'nosync' )
+      else:
+         ebuild_import_nosync = not ebuild_import_nosync
 
 
       overlay_creator.overlay.import_ebuilds (


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

commit:     c65023a5dc2ac5e77f913910f8e9419f801352f3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Sep  2 08:41:39 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Sep  2 08:41:39 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c65023a5

packageinfo: get_src_uri_dest()

identical to get_distmap_key()

---
 roverlay/packageinfo.py | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 43fe4f3..af44450 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -132,6 +132,7 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
       'physical_only',
       'src_uri',
       'has_suggests',
+      'src_uri_dest',
    ))
    _UPDATE_KEYS_SIMPLE_INITIAL = frozenset ((
       'package_filename', 'name',
@@ -554,10 +555,14 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
       )
    # --- end of get_distmap_item (...) ---
 
-   def get_distmap_key ( self ):
-      """Returns a key for the distmap."""
+   def get_src_uri_dest ( self ):
+      """Returns a the package's filesystem path relative to the mirror
+      directory."""
       return self.get ( "package_src_destpath" )
-   # --- end of get_distmap_key (...) ---
+   # --- end of get_src_uri_dest (...) ---
+
+   # which is also the key for distmap entries
+   get_distmap_key = get_src_uri_dest
 
    def get_distmap_value ( self, allow_digest_create=False, no_digest=False ):
       """Returns a data tuple for creating DistMapInfo instances.


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

commit:     b2f292197b8d91de553c312c663d897eaa49d41c
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 30 12:52:40 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 30 12:52:40 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b2f29219

break long line

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

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index abf0dbb..193fe18 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -561,7 +561,8 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
 
    def make_distmap_hash ( self ):
       """Creates (and returns) the distmap package file hash."""
-      return self.make_hashes ( { self.DISTMAP_DIGEST_TYPE, } ) [self.DISTMAP_DIGEST_TYPE]
+      return self.make_hashes (
+         { self.DISTMAP_DIGEST_TYPE, } ) [self.DISTMAP_DIGEST_TYPE]
    # --- end of make_distmap_hash (...) ---
 
    def make_hashes ( self, hashlist ):


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

commit:     40c50b74eb316072732b7170cd3f3f22997c477b
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 30 12:38:31 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 30 12:38:31 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=40c50b74

roverlay/packageinfo: rename get_status_{object,view}

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

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index e991ed7..abf0dbb 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -216,11 +216,11 @@ class PackageInfo ( roverlay.util.objects.Referenceable ):
          return v
    # --- end of has_valid_selfdeps (...) ---
 
-   def get_status_object ( self ):
+   def get_status_view ( self ):
       obj = PackageInfoStatus ( self )
       obj.update()
       return obj
-   # --- end of get_status_object (...) ---
+   # --- end of get_status_view (...) ---
 
    def attach_lazy_action ( self, lazy_action ):
       """Attaches a lazy action.


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

commit:     6778dcf7eff2adc62e616c8ae998ac9e74298c6f
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug 29 12:30:15 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug 29 12:30:15 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6778dcf7

packageinfo: parse SRC_URI, get status view object

---
 roverlay/packageinfo.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index a3be89b..e991ed7 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -17,9 +17,12 @@ import re
 import os.path
 import logging
 
+
 import roverlay.digest
 import roverlay.versiontuple
 import roverlay.db.distmap
+import roverlay.util.objects
+import roverlay.util.ebuildparser
 
 from roverlay          import config, strutil
 from roverlay.rpackage import descriptionreader
@@ -66,7 +69,28 @@ from roverlay.rpackage import descriptionreader
 
 LOGGER = logging.getLogger ( 'PackageInfo' )
 
-class PackageInfo ( object ):
+
+class PackageInfoStatus ( roverlay.util.objects.ObjectView ):
+
+   def __init__ ( self, package_info ):
+      super ( PackageInfoStatus, self ).__init__ ( package_info )
+      self.has_ebuild_file = False
+   # --- end of __init__ (...) ---
+
+   def get_name ( self ):
+      return self.deref_safe().get ( 'name' )
+   # --- end of get_name (...) ---
+
+   def update ( self ):
+      self.has_ebuild_file = bool (
+         self.deref_safe().get ( 'ebuild_file', do_fallback=True )
+      )
+   # --- end of update (...) ---
+
+# --- end of PackageInfoStatus ---
+
+
+class PackageInfo ( roverlay.util.objects.Referenceable ):
    """PackageInfo offers easy, subscriptable access to package
    information, whether stored or calculated.
 
@@ -92,6 +116,8 @@ class PackageInfo ( object ):
                                     called.
    """
 
+   CACHE_REF = True
+
    EBUILDVER_REGEX = re.compile ( '[-]{1,}' )
    PKGSUFFIX_REGEX = re.compile (
       config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$'
@@ -128,6 +154,8 @@ class PackageInfo ( object ):
       arguments:
       * **initial_info -- passed to update ( **kw )
       """
+      super ( PackageInfo, self ).__init__()
+
       self._info    = dict()
       self.readonly = False
       self.logger   = LOGGER
@@ -188,6 +216,12 @@ class PackageInfo ( object ):
          return v
    # --- end of has_valid_selfdeps (...) ---
 
+   def get_status_object ( self ):
+      obj = PackageInfoStatus ( self )
+      obj.update()
+      return obj
+   # --- end of get_status_object (...) ---
+
    def attach_lazy_action ( self, lazy_action ):
       """Attaches a lazy action.
       Unsafe operation (no locks will be acquired etc.).
@@ -684,6 +718,18 @@ class PackageInfo ( object ):
       self._evars [evar.get_pseudo_hash()] = evar
    # --- end of add_evar (...) ---
 
+   def parse_ebuild_src_uri ( self, category_name ):
+      return roverlay.util.ebuildparser.SrcUriParser.from_file (
+         self._info ['ebuild_file'], self.create_vartable ( category_name )
+      )
+   # --- end of parse_ebuild_src_uri (...) ---
+
+   def parse_ebuild_distfiles ( self, category_name ):
+      parser = self.parse_ebuild_src_uri ( category_name )
+      for distfile in parser.iter_local_files():
+         yield distfile
+   # --- end of parse_ebuild_distfiles (...) ---
+
    def get_evars ( self ):
       """Returns all ebuild variables."""
       if hasattr ( self, '_evars' ):


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

commit:     dd5751a54bdeac73478f58f21ffdcff3d2ea9010
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug 29 12:29:27 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug 29 12:29:27 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=dd5751a5

roverlay/status, ReferenceableDict: inherit Referenceable

---
 roverlay/status.py | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/roverlay/status.py b/roverlay/status.py
index 595e8fb..7843380 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -28,6 +28,7 @@ import roverlay.runtime
 import roverlay.tools.shenv
 import roverlay.db.rrdtool
 import roverlay.util.common
+import roverlay.util.objects
 import roverlay.stats.rating
 
 # temporary import
@@ -74,11 +75,7 @@ class DBStats ( roverlay.stats.rating.RoverlayNumStatsRating ):
 # --- end of DBStats ---
 
 
-class ReferenceableDict ( dict ):
-
-   def ref ( self ):
-      return weakref.ref ( self )
-   # --- end of ref (...) ---
+class ReferenceableDict ( roverlay.util.objects.Referenceable, dict ):
 
    def sorted_items ( self, keysort=None ):
       if keysort is None:
@@ -113,7 +110,7 @@ class SelfReferencingDict ( ReferenceableDict ):
 
    def __init__ ( self, *args, **kwargs ):
       super ( SelfReferencingDict, self ).__init__ ( *args, **kwargs )
-      self [self.__class__.SELFREF_KEY] = self.ref()
+      self [self.__class__.SELFREF_KEY] = self.get_ref()
       # or use __getitem__
    # --- end of __init__ (...) ---
 


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

commit:     9db31e67bd33d0486a3499063a4cc0830efb7759
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug 28 15:51:02 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug 28 15:51:02 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9db31e67

packageinfo: create_vartable()

creates a dict with variables like P, PN, PF, ... for "parsing" ebuilds.

---
 roverlay/packageinfo.py | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index b4e38f1..a3be89b 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -861,6 +861,23 @@ class PackageInfo ( object ):
       self._use_filename ( os.path.basename ( filepath ) )
    # --- end of _use_filepath (...) ---
 
+   def create_vartable ( self, category ):
+      PN  = self._info ['name']
+      PV  = str ( self._info ['version'] )
+      PR  = str ( self._info ['rev'] )
+      PVR = PV if PR == '0' else ( PV + '-' + PR )
+
+      return {
+         'P'        : PN + '-' + PV,
+         'PN'       : PN,
+         'PV'       : PV,
+         'PR'       : PR,
+         'PVR'      : PVR,
+         'PF'       : PN + PVR,
+         'CATEGORY' : category,
+      }
+   # --- end of create_vartable (...) ---
+
    def __str__ ( self ):
       return "<PackageInfo for {pkg}>".format (
          pkg=self.get (


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

commit:     2a921c0056de70e4a05169cc7d599b809ede3dd6
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug 27 15:29:26 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug 27 15:29:26 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2a921c00

roverlay/status.py: some comments

---
 roverlay/status.py | 46 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/roverlay/status.py b/roverlay/status.py
index 59c8cb6..595e8fb 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -5,7 +5,6 @@
 # either version 2 of the License, or (at your option) any later version.
 
 # --- TODO/FIXME ---
-# * what happens if the database has UNKNOWNS?
 # * RRA creation doesn't seem to be correct
 #
 
@@ -46,6 +45,28 @@ class DBStats ( roverlay.stats.rating.RoverlayNumStatsRating ):
    # --- end of __init__ (...) ---
 
    def make_suggestions ( self, pure_text=False ):
+      """Creates a list of 2-tuples ( <topic>, list<details> ) with
+      suggestions and stores it as self.suggestions.
+
+      List example:
+      [
+         (
+            "normal/expected failure rate",
+            [
+               "write dependency rules",
+               "configure package ignore rules",
+            ]
+         ),
+         (
+            ...
+         ),
+      ]
+
+      arguments:
+      * pure_text -- disable html tags
+
+      Returns: True if any suggestions available, else False.
+      """
       self.suggestions = list ( self.get_suggestions ( pure_text=pure_text ) )
       return bool ( self.suggestions )
    # --- end of __init__ (...) ---
@@ -53,9 +74,8 @@ class DBStats ( roverlay.stats.rating.RoverlayNumStatsRating ):
 # --- end of DBStats ---
 
 
-
-
 class ReferenceableDict ( dict ):
+
    def ref ( self ):
       return weakref.ref ( self )
    # --- end of ref (...) ---
@@ -178,6 +198,9 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
 
    def do_setup_mako ( self ):
+
+
+      # set up template_dirs / default_template
       template_dirs = []
       self.default_template = 'status'
 
@@ -211,7 +234,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          raise Exception ( "no template directories found!" )
 
 
-
+      # get module root (for caching)
       if 'module_root' in self.options:
          module_dir = self.options ['module_root']
       else:
@@ -230,6 +253,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          # 'python_' + hex ( sys.hexversion>>16 )
 
 
+      # create lookup object
       self._mako_lookup = mako.lookup.TemplateLookup (
          directories=template_dirs, module_directory=module_dir,
          output_encoding=self.TEMPLATE_ENCODING,
@@ -316,6 +340,20 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       file_extensions=[ '', ],
       add_mode_ext=True
    ):
+      """Tries to find a template.
+
+      arguments:
+      * template_name   -- name of the template
+      * file_extensions -- an iterable containing possible file extensions,
+                           in order
+      * add_mode_ext    -- whether to try script_mode-specific file extension
+                            first (Defaults to True).
+
+      Returns: a Template object
+
+      Raises:
+      * Passes mako.exceptions.TopLevelLookupException if template not found
+      """
       my_template = None
 
       if add_mode_ext:


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

commit:     6250f850bd4f8f9708a66df52b2388ebf1f403ba
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 23 11:24:18 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 23 11:24:18 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6250f850

main script, "apply_rules": show modifed deps

---
 roverlay/defaultscript.py | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 1373ee1..7ab2ad0 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -91,9 +91,16 @@ def run_script_main ( installed ):
    if len ( sys.argv ) < 2 or not sys.argv[0]:
       die ( "no executable specified.", DIE.USAGE )
 
+   exe = sys.argv[1]
+   script_file = os.path.abspath ( exe )
+   if os.path.isfile ( script_file ) or os.sep in exe:
+      exe = script_file
+
+   print ( "X___", exe)
+
    roverlay.core.default_helper_setup ( installed )
    roverlay.tools.shenv.run_script_exec (
-      sys.argv[1], "runscript", sys.argv[1:], use_path=True
+      exe, "runscript", sys.argv[1:], use_path=True
    )
 # --- end of run_script_main (...) ---
 
@@ -384,6 +391,24 @@ def run_apply_package_rules ( env ):
                for evar in evars:
                   FH.write ( "* {}\n".format ( evar ) )
 
+            if P.depconf:
+               FH.write ( "dependencies manipulated:\n" )
+               for root_key, subdict in P.depconf.items():
+                  if subdict:
+                     klen = max ( len(s) for s in subdict.keys() )
+
+                     FH.write ( "* {k}\n".format ( k=root_key ) )
+                     for key, deplist in sorted (
+                        subdict.items(), key=( lambda kv: kv[0] ),
+                     ):
+                        for dep in deplist:
+                           FH.write (
+                              "  {key:<{l}} += \"{dep}\"\n".format (
+                                 key=key, dep=dep, l=klen
+                              )
+                           )
+
+
             if P.modified_by_package_rules is not True:
                # ^ check needs to be changed when adding more trace actions
                FH.write ( "trace marks:\n" )


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

commit:     d9a1524c308d0da55a7a63316cfc00729c066545
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 23 11:15:07 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 23 11:15:07 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d9a1524c

roverlay/packageinfo: add depconf attribute

This attribute will be used for storing per-package dependency-related
configuration, e.g. for injecting deps.

---
 roverlay/packageinfo.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 78d20c4..b4e38f1 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -135,6 +135,7 @@ class PackageInfo ( object ):
       self.selfdeps = None
 
       self.hashdict = dict()
+      self.depconf  = None
 
       #self.selfdeps_valid      = UNDEF
       #self.overlay_package_ref = None


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

commit:     2f2f33a397e8fe22cafe701e02ff2d234fbf8758
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 23 11:14:45 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 23 11:14:45 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2f2f33a3

roverlay/core: clean up locate_config_file()

---
 roverlay/core.py | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/roverlay/core.py b/roverlay/core.py
index 8430fd9..2872c48 100644
--- a/roverlay/core.py
+++ b/roverlay/core.py
@@ -138,7 +138,6 @@ def load_config_file (
 def locate_config_file (
    ROVERLAY_INSTALLED, CONFIG_FILE_NAME=DEFAULT_CONFIG_FILE_NAME
 ):
-   DEFAULT_CONFIG_FILE = None
    # search for the config file if roverlay has been installed
    if ROVERLAY_INSTALLED:
       cfg        = None
@@ -147,14 +146,12 @@ def locate_config_file (
       for config_dir in CONFIG_DIRS:
          cfg = config_dir + os.sep + CONFIG_FILE_NAME
          if os.path.isfile ( cfg ):
-            DEFAULT_CONFIG_FILE = cfg
-            break
+            return cfg
 
-      del config_dir, cfg
    elif os.path.exists ( CONFIG_FILE_NAME ):
-      DEFAULT_CONFIG_FILE = CONFIG_FILE_NAME
+      return CONFIG_FILE_NAME
 
-   return DEFAULT_CONFIG_FILE
+   return None
 # --- end of locate_config_file (...) ---
 
 def load_locate_config_file (
@@ -181,6 +178,7 @@ def default_helper_setup ( ROVERLAY_INSTALLED, log_to_console=True ):
       ROVERLAY_INSTALLED, extraconf={ 'installed': ROVERLAY_INSTALLED, },
       setup_logger=False, load_main_only=True,
    )
+
    roverlay.tools.shenv.setup_env()
    return config
 # --- end of default_helper_setup (...) ---


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

commit:     bff3c7b545fb172c1c602a9a8ce7c027a497b151
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Aug 19 15:22:08 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Aug 19 15:22:08 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=bff3c7b5

roverlay/packageinfo: add repo_name, package_filename_x

---
 roverlay/packageinfo.py | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 704807e..78d20c4 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -41,6 +41,7 @@ from roverlay.rpackage import descriptionreader
 # * origin             -- a package's origin (repository object)
 # * package_file       -- full fs path to the package file
 # * package_filename   -- file name (including file extension)
+# * package_filename_x -- file name without file extension
 # * package_name       -- package name (file name without version, f-ext)
 # * physical_only      -- bool that indicates whether a package exists as
 #                          ebuild file only (True) or has additional
@@ -99,7 +100,6 @@ class PackageInfo ( object ):
    ALWAYS_FALLBACK = frozenset ( ( 'ebuild', 'ebuild_file' ) )
 
    _UPDATE_KEYS_SIMPLE         = frozenset ((
-      'origin',
       'ebuild',
       'ebuild_file',
       'imported',
@@ -710,6 +710,10 @@ class PackageInfo ( object ):
             if value is not None:
                self._info [key] = value
 
+         elif key == 'origin':
+            self._info ['origin'] = value
+            self._info ['repo_name'] = value.name
+
          elif key == 'filename':
             self._use_filename ( value )
 
@@ -792,12 +796,12 @@ class PackageInfo ( object ):
       ebuild_name = strutil.fix_ebuild_name ( package_name )
 
       # for DescriptionReader
-      self._info ['package_name']     = package_name
-
-      self._info ['rev']              = 0
-      self._info ['name']             = ebuild_name
-      self._info ['ebuild_verstr']    = version_str
-      self._info ['package_filename'] = filename_with_ext
+      self._info ['package_name']       = package_name
+      self._info ['rev']                = 0
+      self._info ['name']               = ebuild_name
+      self._info ['ebuild_verstr']      = version_str
+      self._info ['package_filename']   = filename_with_ext
+      self._info ['package_filename_x'] = filename
    # --- end of _use_filename (...) ---
 
    def _use_pvr ( self, pvr ):


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

commit:     83298a990357b3511dcd32b23fa4f4e446f4c79c
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 14:05:01 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 14:05:01 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=83298a99

status script: accept --module-root arg

This allows to use another user's config file when running in cgi mode.

---
 roverlay/argparser.py |  7 +++++++
 roverlay/status.py    | 14 +++++++++-----
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 7b7d9e9..0a73c9b 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -594,6 +594,13 @@ class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
          help='cgi content type',
       )
 
+      arg (
+         '-M', '--module-root', dest='module_root',
+         default=argparse.SUPPRESS, metavar="<dir>",
+         type=couldbe_fs_dir,
+         help="directory for storing cached templates",
+      )
+
 ##      arg (
 ##         '-o', '--template-options', dest='template_options',
 ##         metavar='<option>', action='append',

diff --git a/roverlay/status.py b/roverlay/status.py
index 617aaab..59c8cb6 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -211,11 +211,15 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          raise Exception ( "no template directories found!" )
 
 
-      module_dir = self.config.get ( 'STATS.TEMPLATE.module_dir', None )
-      if module_dir is None:
-         module_dir = self.config.get ( 'CACHEDIR.root', None )
-         if module_dir:
-            module_dir += os.sep + 'mako_templates'
+
+      if 'module_root' in self.options:
+         module_dir = self.options ['module_root']
+      else:
+         module_dir = self.config.get ( 'STATS.TEMPLATE.module_dir', None )
+         if module_dir is None:
+            module_dir = self.config.get ( 'CACHEDIR.root', None )
+            if module_dir:
+               module_dir += os.sep + 'mako_templates'
 
       # use per-version module dirs
       #  modules generated with python2.7 are not compatible with python3.2


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

commit:     faadf46ac9cbd3927498d68ea15c306b808f82b3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 11:01:45 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 11:01:45 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=faadf46a

roverlay/status: fix mako templates location

... when installed

---
 roverlay/status.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/roverlay/status.py b/roverlay/status.py
index 2a80977..617aaab 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -200,6 +200,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       if self.installed:
          template_dirs.append (
             self.config.get_or_fail ( 'INSTALLINFO.libexec' )
+            + os.sep + 'mako_templates'
          )
 
       extra_dirs = self.config.get ( 'STATS.TEMPLATE.root' )


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

commit:     b6c49313277e4685bc63c1b8f1c5983253b19d66
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 10:24:24 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 10:26:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b6c49313

roverlay/status: use stats rating

Other change:
* some example_graph() experiments
* moved "find template" functionality from serve_template() to get_template()
* TODO notes (RRA creation,UNKNOWNS)
* write mako modules to python-version specific subdirectories

---
 roverlay/status.py | 169 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 114 insertions(+), 55 deletions(-)

diff --git a/roverlay/status.py b/roverlay/status.py
index 5e68301..2a80977 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -4,6 +4,11 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
+# --- TODO/FIXME ---
+# * what happens if the database has UNKNOWNS?
+# * RRA creation doesn't seem to be correct
+#
+
 from __future__ import print_function
 
 import os
@@ -24,11 +29,32 @@ import roverlay.runtime
 import roverlay.tools.shenv
 import roverlay.db.rrdtool
 import roverlay.util.common
+import roverlay.stats.rating
 
 # temporary import
 import roverlay.db.rrdgraph
 
 
+class DBStats ( roverlay.stats.rating.RoverlayNumStatsRating ):
+
+   def __init__ ( self, db_cache, description=None ):
+      super ( DBStats, self ).__init__ (
+         db_cache['values'], description=description
+      )
+      self.lastupdate = db_cache['lastupdate']
+      self.suggestions = None
+   # --- end of __init__ (...) ---
+
+   def make_suggestions ( self, pure_text=False ):
+      self.suggestions = list ( self.get_suggestions ( pure_text=pure_text ) )
+      return bool ( self.suggestions )
+   # --- end of __init__ (...) ---
+
+# --- end of DBStats ---
+
+
+
+
 class ReferenceableDict ( dict ):
    def ref ( self ):
       return weakref.ref ( self )
@@ -80,8 +106,9 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
    TEMPLATE_ENCODING = 'utf-8'
 
    SCRIPT_MODE_FILE_EXT = {
-      'cgi': '.html',
-      'cli': '.txt',
+      'cli' : '.txt',
+      'cgi' : '.html',
+      'html': '.html',
    }
 
    # variables from /etc/nginx/fastcgi.conf
@@ -152,8 +179,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
    def do_setup_mako ( self ):
       template_dirs = []
-      if not getattr ( self, 'default_template', None ):
-         self.default_template = self.script_mode
+      self.default_template = 'status'
 
       if 'template' in self.options:
          # not ideal, but should suffice
@@ -190,6 +216,14 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          if module_dir:
             module_dir += os.sep + 'mako_templates'
 
+      # use per-version module dirs
+      #  modules generated with python2.7 are not compatible with python3.2
+      if module_dir:
+         module_dir += ( os.sep +
+            'python_' + '.'.join ( map ( str, sys.version_info[:2] ) )
+         )
+         # 'python_' + hex ( sys.hexversion>>16 )
+
 
       self._mako_lookup = mako.lookup.TemplateLookup (
          directories=template_dirs, module_directory=module_dir,
@@ -222,10 +256,11 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       if self.outfile == '-':
          self.outfile = None
 
-      self.set_template_vars (
-         EXE=sys.argv[0], EXE_NAME=os.path.basename ( sys.argv[0] ),
-         SCRIPT_MODE=script_mode
-      )
+      self.template_vars ['EXE']         = sys.argv[0]
+      self.template_vars ['EXE_NAME']    = os.path.basename ( sys.argv[0] )
+      self.template_vars ['SCRIPT_MODE'] = script_mode
+
+
 
       if script_mode == 'cgi':
          # inherit cgi-related vars from os.environ
@@ -244,6 +279,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       self.stats_db      = None
       self.graph_factory = None
       stats_db_file      = self.config.get ( 'RRD_DB.file', None )
+
       if stats_db_file:
          self.stats_db = roverlay.db.rrdtool.RRD (
             stats_db_file, readonly=True
@@ -252,62 +288,74 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          self.graph_factory = roverlay.db.rrdgraph.RRDGraphFactory (
             rrd_db=self.stats_db,
         )
-      # -- end if
 
 
-      # transfer db cache to template_vars
-      # * copy lastupdate
-      # * import values
-      #
-      self.set_template_vars (
-         self.stats_db.cache ['values'],
-         lastupdate=self.stats_db.cache ['lastupdate'],
-         STATS_DB=self.stats_db, STATS_DB_FILE=stats_db_file,
-      )
+         # transfer db cache to template_vars
+         # * copy lastupdate
+         # * import values
+         #
+         self.set_template_vars (
+            self.stats_db.cache ['values'],
+            lastupdate=self.stats_db.cache ['lastupdate'],
+            STATS_DB_FILE=stats_db_file,
+            STATS_DB=DBStats ( self.stats_db.cache ),
+         )
+
+      # -- end if
 
       self.do_setup_mako()
    # --- end of do_setup (...) ---
 
-   def serve_template ( self,
-      template_name    = None,
-      file_extensions  = [ '', '.mako', '.tmpl' ],
-      append_mode_ext  = True,
-      catch_exceptions = True,
+   def get_template ( self,
+      template_name,
+      file_extensions=[ '', ],
+      add_mode_ext=True
    ):
-      try:
-         my_template_name = (
-            template_name if template_name is not None
-            else self.default_template
-         )
+      my_template = None
 
-         if append_mode_ext:
-            fext_list = list ( file_extensions )
-            fext_list.append ( self.get_script_mode_file_ext() )
+      if add_mode_ext:
+         fext_list = (
+            [ self.get_script_mode_file_ext() ] + list ( file_extensions )
+         )
+      else:
+         fext_list = file_extensions
+
+      # TODO/FIXME: does TemplateLookup support file extension_s_ lookup?
+      last_fext_index = len ( fext_list ) - 1
+      for index, f_ext in enumerate ( fext_list ):
+         if index == last_fext_index:
+            my_template = self._mako_lookup.get_template (
+               template_name + f_ext
+            )
          else:
-            fext_list = file_extensions
-
-         # TODO/FIXME: does TemplateLookup support file extension_s_ lookup?
-         last_fext_index = len ( fext_list ) - 1
-         for index, f_ext in enumerate ( fext_list ):
-            if index == last_fext_index:
+            try:
                my_template = self._mako_lookup.get_template (
-                  my_template_name + f_ext
+                  template_name + f_ext
                )
+            except mako.exceptions.TopLevelLookupException:
+               pass
             else:
-               try:
-                  my_template = self._mako_lookup.get_template (
-                     my_template_name + f_ext
-                  )
-               except mako.exceptions.TopLevelLookupException:
-                  pass
-               else:
-                  break
-            # -- end if
+               break
+         # -- end if
 
+      return my_template
+   # --- end of get_template (...) ---
+
+   def serve_template ( self,
+      template_name=None, catch_exceptions=True, lookup_kwargs={}
+   ):
+      try:
+         my_template = self.get_template (
+            template_name=(
+               template_name if template_name is not None
+               else self.default_template
+            ),
+            **lookup_kwargs
+         )
          ret = my_template.render ( **self.template_vars )
       except:
          if catch_exceptions:
-            if self.script_mode == 'cgi':
+            if self.script_mode in { 'cgi', 'html' }:
                ret = mako.exceptions.html_error_template().render()
             else:
                ret = mako.exceptions.text_error_template().render()
@@ -373,7 +421,7 @@ def graph_example ( main_env, dump_file="/tmp/roverlay_graph.png" ):
    ]
 
    graph.end   = "now"
-   graph.start = "end-" + str ( graph.SECONDS_DAY/4 ) + "s"
+   graph.start = "end-" + str ( graph.SECONDS_DAY//4 ) + "s"
    graph.extra_options.extend ((
       '--width', '400', '--border', '0',
       '--font', 'DEFAULT:0:DejaVuSans,DejaVu Sans,DejaVu LGC Sans,Bitstream Vera Sans',
@@ -381,17 +429,28 @@ def graph_example ( main_env, dump_file="/tmp/roverlay_graph.png" ):
 
    ))
 
-   graph.add_def  ( "pkg_success", "pc_success", "LAST" )
-   graph.add_def  ( "pkg_fail",  "pc_fail", "LAST" )
+   graph.add_def  ( "pkg_success", "pc_success", "MAX" )
+   graph.add_def  ( "pkg_fail",  "pc_fail", "MAX" )
 
    graph.add_vdef ( "pkg_success_max", "pkg_success,MAXIMUM" )
+   graph.add_vdef ( "pkg_success_min", "pkg_success,MINIMUM" )
    graph.add_vdef ( "pkg_fail_max",  "pkg_fail,MAXIMUM" )
+   graph.add_vdef ( "pkg_fail_min",  "pkg_fail,MINIMUM" )
+
+   graph.add_arg ( "COMMENT:            " )
+   graph.add_arg ( "COMMENT:     min " )
+   graph.add_arg ( "COMMENT:     max\l" )
+
+   graph.add_line ( "pkg_success", "blue", width=1, legend="pkg success" )
+   graph.add_print ( "pkg_success_min", "%7.0lf %S", inline=True )
+   graph.add_print ( "pkg_success_max", "%7.0lf %S\l", inline=True )
+
 
-   graph.add_line ( "pkg_success", "blue", width=4, legend="pkg success" )
-   graph.add_print ( "pkg_success_max", "%.2lf %S\l", inline=True )
 
-   graph.add_line ( "pkg_fail", "red",  width=4, legend="pkg fail   " )
-   graph.add_print ( "pkg_fail_max", "%.2lf %S\l", inline=True )
+   #graph.add_line ( "pkg_fail", "red",  width=1, legend="pkg fail   " )
+   graph.add_area ( "pkg_fail", "red", legend="pkg fail   " )
+   graph.add_print ( "pkg_fail_min", "%7.0lf %S", inline=True )
+   graph.add_print ( "pkg_fail_max", "%7.0lf %S\l", inline=True )
 
    graph.make()
 


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

commit:     818bfa863c7da84c37fc45871c84c5dbe67ac9af
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 10:18:58 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 10:18:58 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=818bfa86

roverlay/argparser, status scritp: add 'html' mode

Similar to the 'cgi' mode, but doesn't print the "Content-Type: ..." header.

---
 roverlay/argparser.py | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index a01d1c9..7b7d9e9 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -544,7 +544,7 @@ class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
    }
    DEFAULT_COMMAND = 'status'
 
-   MODES = frozenset ({ 'cgi', 'cli' })
+   MODES = ( 'cli', 'cgi', 'html', )
    DEFAULT_MODE = 'cli'
 
    def setup_script_mode ( self ):
@@ -588,11 +588,18 @@ class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
       )
 
       arg (
-         '--cgi-content-type', dest='cgi_content_type', default="text/html",
+         '-T', '--cgi-content-type', dest='cgi_content_type',
+         default="text/html",
          flags=self.ARG_WITH_DEFAULT, metavar='<type>',
          help='cgi content type',
       )
 
+##      arg (
+##         '-o', '--template-options', dest='template_options',
+##         metavar='<option>', action='append',
+##         help='pass arbitrary options to templates',
+##      )
+
       return arg
    # --- end of setup_output_options (...) ---
 


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

commit:     4827a57fe083426e9d0c9c4637f9ae551565edd1
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug 14 14:54:59 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug 14 14:55:13 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4827a57f

roverlay/status: graph creation example

---
 roverlay/status.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/roverlay/status.py b/roverlay/status.py
index 56a2d61..5e68301 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -25,6 +25,9 @@ import roverlay.tools.shenv
 import roverlay.db.rrdtool
 import roverlay.util.common
 
+# temporary import
+import roverlay.db.rrdgraph
+
 
 class ReferenceableDict ( dict ):
    def ref ( self ):
@@ -149,7 +152,8 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
    def do_setup_mako ( self ):
       template_dirs = []
-      self.default_template = self.script_mode
+      if not getattr ( self, 'default_template', None ):
+         self.default_template = self.script_mode
 
       if 'template' in self.options:
          # not ideal, but should suffice
@@ -190,7 +194,6 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       self._mako_lookup = mako.lookup.TemplateLookup (
          directories=template_dirs, module_directory=module_dir,
          output_encoding=self.TEMPLATE_ENCODING,
-         #future_imports=[ 'print_function', 'division', ],
       )
    # --- end of do_setup_mako (...) ---
 
@@ -232,15 +235,24 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
             ),
             CGI_FORM=cgi.FieldStorage( keep_blank_values=0 ),
          )
+         # TODO (maybe):
+         #  set default_template depending on CGI_FORM
+         #
+      # -- end if
 
 
-      self.stats_db = None
-      stats_db_file = self.config.get ( 'RRD_DB.file', None )
+      self.stats_db      = None
+      self.graph_factory = None
+      stats_db_file      = self.config.get ( 'RRD_DB.file', None )
       if stats_db_file:
          self.stats_db = roverlay.db.rrdtool.RRD (
             stats_db_file, readonly=True
          )
          self.stats_db.make_cache()
+         self.graph_factory = roverlay.db.rrdgraph.RRDGraphFactory (
+            rrd_db=self.stats_db,
+        )
+      # -- end if
 
 
       # transfer db cache to template_vars
@@ -345,6 +357,50 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
 # --- end of StatusRuntimeEnvironment ---
 
+def graph_example ( main_env, dump_file="/tmp/roverlay_graph.png" ):
+   """graph creation - work in progress"""
+
+   graph = main_env.graph_factory.get_new()
+   graph.title = "R_Overlay"
+   graph.colors = [
+      # colors from munin (Munin::Master::GraphOld[.pm])
+      'BACK#F0F0F0',   # Area around the graph
+      'FRAME#F0F0F0',  # Line around legend spot
+      'CANVAS#FFFFFF', # Graph background, max contrast
+      'FONT#666666',   # Some kind of gray
+      'AXIS#CFD6F8',   # And axis like html boxes
+      'ARROW#CFD6F8',  # And arrow, ditto.
+   ]
+
+   graph.end   = "now"
+   graph.start = "end-" + str ( graph.SECONDS_DAY/4 ) + "s"
+   graph.extra_options.extend ((
+      '--width', '400', '--border', '0',
+      '--font', 'DEFAULT:0:DejaVuSans,DejaVu Sans,DejaVu LGC Sans,Bitstream Vera Sans',
+      '--font', 'LEGEND:7:DejaVuSansMono,DejaVu Sans Mono,DejaVu LGC Sans Mono,Bitstream Vera Sans Mono,monospace',
+
+   ))
+
+   graph.add_def  ( "pkg_success", "pc_success", "LAST" )
+   graph.add_def  ( "pkg_fail",  "pc_fail", "LAST" )
+
+   graph.add_vdef ( "pkg_success_max", "pkg_success,MAXIMUM" )
+   graph.add_vdef ( "pkg_fail_max",  "pkg_fail,MAXIMUM" )
+
+   graph.add_line ( "pkg_success", "blue", width=4, legend="pkg success" )
+   graph.add_print ( "pkg_success_max", "%.2lf %S\l", inline=True )
+
+   graph.add_line ( "pkg_fail", "red",  width=4, legend="pkg fail   " )
+   graph.add_print ( "pkg_fail_max", "%.2lf %S\l", inline=True )
+
+   graph.make()
+
+   image = graph.get_image()
+   if image:
+      with open ( dump_file, 'wb' ) as FH:
+         FH.write ( graph.get_image() )
+
+# --- end of graph_example (...) ---
 
 def main_installed ( *args, **kwargs ):
    return main ( True, *args, **kwargs )
@@ -355,6 +411,8 @@ def main ( installed, *args, **kw ):
    main_env = StatusRuntimeEnvironment ( installed, *args, **kw )
    main_env.setup()
 
+   #graph_example ( main_env )
+
    output_encoded = main_env.serve_template()
 
    if main_env.outfile:


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

commit:     58094496a2b1393988a81f297ef62e3db4612937
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug 13 12:07:29 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug 13 12:07:29 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=58094496

roverlay/status: smart(er) template file lookup

automatically append file extensions when searching for the template file,
depending on the script mode ('.html' for cgi, '.txt' for cli).

---
 roverlay/argparser.py |  7 ++---
 roverlay/status.py    | 80 ++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 72 insertions(+), 15 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 84e1478..a01d1c9 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -523,7 +523,7 @@ class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
    # --- end of setup_actions (...) ---
 
    def parse_actions ( self ):
-      command = self.parsed ['command']
+      self.command = self.parsed ['command']
    # --- end of parse_actions (...) ---
 
 # --- end of RoverlayArgumentParser ---
@@ -583,9 +583,8 @@ class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
 
       arg (
          '-t', '--template', dest='template', default=argparse.SUPPRESS,
-         flags=self.ARG_WITH_DEFAULT|self.ARG_META_FILE,
-         type=is_fs_file,
-         help='template file for generating output',
+         flags=self.ARG_ADD_DEFAULT, metavar='<file|name>',
+         help='template file or name for generating output',
       )
 
       arg (

diff --git a/roverlay/status.py b/roverlay/status.py
index 7872674..56a2d61 100644
--- a/roverlay/status.py
+++ b/roverlay/status.py
@@ -5,7 +5,6 @@
 # either version 2 of the License, or (at your option) any later version.
 
 from __future__ import print_function
-#from __future__ import division
 
 import os
 import sys
@@ -39,6 +38,14 @@ class ReferenceableDict ( dict ):
          return sorted ( self.items(), key=lambda kv: keysort ( kv[0] ) )
    # --- end of sorted_items (...) ---
 
+   def sorted_env_vars ( self, keysort=None ):
+      # return list with "scalar" types only
+      return list (
+         kv for kv in self.sorted_items ( keysort=keysort )
+            if isinstance ( kv[1], ( str, int, float ) )
+      )
+   # --- end of sorted_env_vars (...) ---
+
 # --- end of ReferenceableDict ---
 
 class SelfReferencingDict ( ReferenceableDict ):
@@ -69,6 +76,11 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
    TEMPLATE_ENCODING = 'utf-8'
 
+   SCRIPT_MODE_FILE_EXT = {
+      'cgi': '.html',
+      'cli': '.txt',
+   }
+
    # variables from /etc/nginx/fastcgi.conf
    #  (will be kept in template env dict depending on script mode)
    #
@@ -137,16 +149,22 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
 
    def do_setup_mako ( self ):
       template_dirs = []
+      self.default_template = self.script_mode
 
       if 'template' in self.options:
-         dirname, basename = os.path.split (
+         # not ideal, but should suffice
+         #  otherwise, introduce a --template-name arg
+         #
+         fspath = os.path.abspath (
             self.options ['template'].rstrip ( os.sep )
          )
-         assert dirname and basename
-         template_dirs.append ( dirname )
-         self.default_template = basename
-      else:
-         self.default_template = self.script_mode
+         if os.path.isfile ( fspath ):
+            dirname, basename = os.path.split ( fspath )
+            assert dirname and basename
+            template_dirs.append ( dirname )
+            self.default_template = basename
+         else:
+            self.default_template = self.options ['template']
       # -- end if
 
       if self.installed:
@@ -172,6 +190,7 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       self._mako_lookup = mako.lookup.TemplateLookup (
          directories=template_dirs, module_directory=module_dir,
          output_encoding=self.TEMPLATE_ENCODING,
+         #future_imports=[ 'print_function', 'division', ],
       )
    # --- end of do_setup_mako (...) ---
 
@@ -187,6 +206,8 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          roverlay.tools.shenv.setup_env()
       )
       roverlay.tools.shenv.restore_msg_vars ( self.template_vars )
+      #self.template_vars ['ROVERLAY_PHASE'] = 'status_' + self.command
+      self.template_vars ['ROVERLAY_PHASE'] = 'status'
 
       try:
          del self.template_vars ['STATS_DB']
@@ -235,12 +256,42 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
       self.do_setup_mako()
    # --- end of do_setup (...) ---
 
-   def serve_template ( self, template_name=None, catch_exceptions=True ):
+   def serve_template ( self,
+      template_name    = None,
+      file_extensions  = [ '', '.mako', '.tmpl' ],
+      append_mode_ext  = True,
+      catch_exceptions = True,
+   ):
       try:
-         my_template = self._mako_lookup.get_template (
+         my_template_name = (
             template_name if template_name is not None
             else self.default_template
          )
+
+         if append_mode_ext:
+            fext_list = list ( file_extensions )
+            fext_list.append ( self.get_script_mode_file_ext() )
+         else:
+            fext_list = file_extensions
+
+         # TODO/FIXME: does TemplateLookup support file extension_s_ lookup?
+         last_fext_index = len ( fext_list ) - 1
+         for index, f_ext in enumerate ( fext_list ):
+            if index == last_fext_index:
+               my_template = self._mako_lookup.get_template (
+                  my_template_name + f_ext
+               )
+            else:
+               try:
+                  my_template = self._mako_lookup.get_template (
+                     my_template_name + f_ext
+                  )
+               except mako.exceptions.TopLevelLookupException:
+                  pass
+               else:
+                  break
+            # -- end if
+
          ret = my_template.render ( **self.template_vars )
       except:
          if catch_exceptions:
@@ -286,6 +337,12 @@ class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
          return str ( data )
    # --- end of decode (...) ---
 
+   def get_script_mode_file_ext ( self ):
+      return self.SCRIPT_MODE_FILE_EXT.get (
+         self.script_mode, ( '.' + self.script_mode )
+      )
+   # --- end of get_script_mode_file_ext (...) ---
+
 # --- end of StatusRuntimeEnvironment ---
 
 
@@ -294,6 +351,7 @@ def main_installed ( *args, **kwargs ):
 # --- end of main_installed (...) ---
 
 def main ( installed, *args, **kw ):
+
    main_env = StatusRuntimeEnvironment ( installed, *args, **kw )
    main_env.setup()
 
@@ -308,7 +366,7 @@ def main ( installed, *args, **kw ):
          #main_env.write_cgi_header ( FH, encode=True )
          FH.write ( output_encoded )
    else:
-      output = main_env.decode ( output_encoded )
-      main_env.write_cgi_header ( sys.stdout, force=True )
+      output = main_env.decode ( output_encoded ).lstrip ( '\n' )
+      main_env.write_cgi_header ( sys.stdout )
       sys.stdout.write ( output )
 # --- end of main (...) ---


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

commit:     4cef51017af1d97fa4c75625fcabc351486804cb
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug 13 08:42:54 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug 13 08:42:54 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4cef5101

roverlay/runtime: make runtime object modular

split RuntimeEnvironment into a common (RuntimeEnvironmentBase) and a "main
script"-specific part (RuntimeEnvironment, as before).

The runtime object does no longer set up itself in __init__(), setup() has to be
called manually now.

---
 roverlay/defaultscript.py |   1 +
 roverlay/runtime.py       | 144 +++++++++++++++++++++++++++-------------------
 2 files changed, 85 insertions(+), 60 deletions(-)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index dfbe29d..8c629f8 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -35,6 +35,7 @@ def main_installed ( *args, **kw ):
 
 def main ( installed, *args, **kw ):
    main_env = roverlay.runtime.RuntimeEnvironment ( installed, *args, **kw )
+   main_env.setup()
 
    if main_env.want_command ( 'setupdirs' ):
       sys.exit ( run_setupdirs ( main_env ) )

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index 81a7726..a65555d 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -18,113 +18,137 @@ import roverlay.stats.collector
 
 from roverlay.core import DIE, die
 
+class RuntimeEnvironmentBase ( object ):
+
+   ARG_PARSER_CLS  = None
+   KEEP_ARG_PARSER = False
 
-class RuntimeEnvironment ( object ):
    def __init__ ( self,
       installed,
       hide_exceptions=False,
       config_file_name=roverlay.core.DEFAULT_CONFIG_FILE_NAME
    ):
-      super ( RuntimeEnvironment, self ).__init__()
-
+      super ( RuntimeEnvironmentBase, self ).__init__()
       self.logger            = logging.getLogger()
+      self.installed         = bool ( installed )
+      self.hide_exceptions   = bool ( hide_exceptions )
+      self.config_file_name  = str ( config_file_name )
       self.HLINE             = 79 * '-'
+
       self.stats             = roverlay.stats.collector.static
       self.config            = None
       self.additional_config = None
       self.options           = None
-      self.actions_done      = set()
       self.command           = None
+   # --- end of __init__ (...) ---
 
-      self._repo_list        = None
-      self._overlay_creator  = None
-      self.stats_db_file     = None
-
-      self.want_db_commit    = False
-
-      self.hide_exceptions = hide_exceptions
-      if hide_exceptions:
+   def setup ( self ):
+      roverlay.core.setup_initial_logger()
+      self.stats.time.begin ( "setup" )
+      if self.hide_exceptions:
          try:
-            self.setup ( installed, config_file_name )
+            self.do_setup()
          except:
             die ( "failed to initialize runtime environment." )
       else:
-         self.setup ( installed, config_file_name )
-   # --- end of __init__ (...) ---
-
-   def get_repo_list ( self ):
-      if self._repo_list is None:
-         self._repo_list = roverlay.remote.repolist.RepoList (
-            sync_enabled   = not self.config.get_or_fail ( 'nosync' ),
-            force_distroot = self.options.get ( 'force_distroot' )
-         )
-      return self._repo_list
-   # --- end of get_repo_list (...) ---
-
-   def get_overlay_creator ( self ):
-      if self._overlay_creator is None:
-         self._overlay_creator = roverlay.overlay.creator.OverlayCreator (
-            skip_manifest           = not self.options ['manifest'],
-            incremental             = self.options ['incremental'],
-            allow_write             = self.options ['write_overlay'],
-            immediate_ebuild_writes = self.options ['immediate_ebuild_writes'],
-         )
-      return self._overlay_creator
-   # --- end of get_overlay_creator (...) ---
-
-   def setup ( self, installed, config_file_name ):
-      roverlay.core.setup_initial_logger()
-      self.stats.time.begin ( "setup" )
+         self.do_setup()
+      self.stats.time.end ( "setup" )
+   # --- end of setup (...) ---
 
-      parser = roverlay.argparser.RoverlayMainArgumentParser (
+   def do_setup_parser ( self ):
+      parser = self.ARG_PARSER_CLS (
          defaults={
             'config_file': roverlay.core.locate_config_file (
-               installed, config_file_name
+               self.installed, self.config_file_name
             )
          }
       )
       parser.setup()
       parser.parse()
-      parser.do_extraconf ( installed, 'installed' )
-
-      command           = parser.command
-      options           = parser.parsed
-      additional_config = parser.extra_conf
+      parser.do_extraconf ( self.installed, 'installed' )
 
-      del parser
+      self.command           = getattr ( parser, 'command', None )
+      self.options           = parser.parsed
+      self.additional_config = parser.extra_conf
 
+      if self.KEEP_ARG_PARSER:
+         self.parser = parser
+   # --- end of do_setup_parser (...) ---
 
+   def do_setup_config ( self ):
       try:
          self.config = roverlay.core.load_config_file (
-            options ['config_file'],
-            extraconf      = additional_config,
-            setup_logger   = options ['want_logging'],
-            load_main_only = options ['load_main_only'],
+            self.options ['config_file'],
+            extraconf      = self.additional_config,
+            setup_logger   = self.options.get ( 'want_logging', False ),
+            load_main_only = self.options.get ( 'load_main_only', True ),
          )
       except:
          if self.hide_exceptions:
             die (
                "Cannot load config file {!r}".format (
-                  options ['config_file']
+                  self.options ['config_file']
                ),
                DIE.CONFIG
             )
          else:
             raise
+   # --- end of do_setup_config (...) ---
+
+   def do_setup ( self ):
+      self.do_setup_parser()
+      self.do_setup_config()
+   # --- end of do_setup (...) ---
+
+# --- end of RuntimeEnvironmentBase (...) ---
+
+class RuntimeEnvironment ( RuntimeEnvironmentBase ):
 
+   ARG_PARSER_CLS = roverlay.argparser.RoverlayMainArgumentParser
 
-      self.stats_db_file     = self.config.get ( 'RRD_DB.file', None )
-      self.command           = command
-      self.options           = options
-      self.additional_config = additional_config
+   def __init__ ( self, installed, *args, **kw ):
+      super ( RuntimeEnvironment, self ).__init__ ( installed, *args, **kw )
+
+      self.actions_done     = set()
+      self.command          = None
+
+      self.stats_db_file    = None
+      self.want_db_commit   = False
+
+      self._repo_list       = None
+      self._overlay_creator = None
+   # --- end of __init__ (...) ---
 
+   def get_repo_list ( self ):
+      if self._repo_list is None:
+         self._repo_list = roverlay.remote.repolist.RepoList (
+            sync_enabled   = not self.config.get_or_fail ( 'nosync' ),
+            force_distroot = self.options.get ( 'force_distroot' )
+         )
+      return self._repo_list
+   # --- end of get_repo_list (...) ---
+
+   def get_overlay_creator ( self ):
+      if self._overlay_creator is None:
+         self._overlay_creator = roverlay.overlay.creator.OverlayCreator (
+            skip_manifest           = not self.options ['manifest'],
+            incremental             = self.options ['incremental'],
+            allow_write             = self.options ['write_overlay'],
+            immediate_ebuild_writes = self.options ['immediate_ebuild_writes'],
+         )
+      return self._overlay_creator
+   # --- end of get_overlay_creator (...) ---
+
+   def do_setup ( self ):
+      self.do_setup_parser()
+      self.do_setup_config()
+
+      self.stats_db_file = self.config.get ( 'RRD_DB.file', None )
 
       # want_logging <=> <have a command that uses hooks>
-      if options ['want_logging']:
+      if self.options ['want_logging']:
          roverlay.hook.setup()
-
-      self.stats.time.end ( "setup" )
-   # --- end of setup (...) ---
+   # --- end of do_setup (...) ---
 
    def setup_database ( self ):
       if self.stats_db_file:


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

commit:     a5254ba1cab1dde89f78a9552373dd342de8ae97
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug 13 08:50:12 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug 13 08:50:12 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a5254ba1

roverlay/status: status report generation

roverlay/status creates an environment for generating status reports based on
mako templates. CGI mode is supported, too ("--cgi").

---
 roverlay/status.py | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 314 insertions(+)

diff --git a/roverlay/status.py b/roverlay/status.py
new file mode 100644
index 0000000..7872674
--- /dev/null
+++ b/roverlay/status.py
@@ -0,0 +1,314 @@
+# R overlay -- create status reports based on templates
+# -*- 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
+#from __future__ import division
+
+import os
+import sys
+import cgi
+import cgitb
+import weakref
+
+
+# using mako
+import mako.exceptions
+import mako.lookup
+import mako.template
+
+
+import roverlay.argparser
+import roverlay.runtime
+import roverlay.tools.shenv
+import roverlay.db.rrdtool
+import roverlay.util.common
+
+
+class ReferenceableDict ( dict ):
+   def ref ( self ):
+      return weakref.ref ( self )
+   # --- end of ref (...) ---
+
+   def sorted_items ( self, keysort=None ):
+      if keysort is None:
+         return sorted ( self.items(), key=lambda kv: kv[0] )
+      else:
+         return sorted ( self.items(), key=lambda kv: keysort ( kv[0] ) )
+   # --- end of sorted_items (...) ---
+
+# --- end of ReferenceableDict ---
+
+class SelfReferencingDict ( ReferenceableDict ):
+   SELFREF_KEY = 'dictref'
+
+##   def __setitem__ ( self, key, *args, **kw ):
+##      if key == self.__class__.SELFREF_KEY:
+##         raise AttributeError (
+##            "{!r} is readonly.".format ( self.__class__.SELFREF_KEY )
+##         )
+##      else:
+##         return super ( SelfReferencingDict, self ).__setitem__ (
+##            key, *args, **kw
+##         )
+##   # --- end of __setitem__ (...) ---
+
+   def __init__ ( self, *args, **kwargs ):
+      super ( SelfReferencingDict, self ).__init__ ( *args, **kwargs )
+      self [self.__class__.SELFREF_KEY] = self.ref()
+      # or use __getitem__
+   # --- end of __init__ (...) ---
+
+# --- end of SelfReferencingDict ---
+
+
+class StatusRuntimeEnvironment ( roverlay.runtime.RuntimeEnvironmentBase ):
+   ARG_PARSER_CLS = roverlay.argparser.RoverlayStatusArgumentParser
+
+   TEMPLATE_ENCODING = 'utf-8'
+
+   # variables from /etc/nginx/fastcgi.conf
+   #  (will be kept in template env dict depending on script mode)
+   #
+   #  sed -nr -e 's,^fastcgi_param\s+(\S+)\s+.*$,"\1"\,,p' \
+   #     /etc/nginx/fastcgi.conf | sort
+   #
+   NGINX_CGI_VARS = frozenset ({
+      "CONTENT_LENGTH",
+      "CONTENT_TYPE",
+      "DOCUMENT_ROOT",
+      "DOCUMENT_URI",
+      "GATEWAY_INTERFACE",
+      "HTTPS",
+      "QUERY_STRING",
+      "REDIRECT_STATUS",
+      "REMOTE_ADDR",
+      "REMOTE_PORT",
+      "REQUEST_METHOD",
+      "REQUEST_URI",
+      "SCRIPT_FILENAME",
+      "SCRIPT_NAME",
+      "SERVER_ADDR",
+      "SERVER_NAME",
+      "SERVER_PORT",
+      "SERVER_PROTOCOL",
+      "SERVER_SOFTWARE",
+   })
+
+   # common cgi vars as listed in
+   #  /usr/lib/python3.2/cgi.py
+   #
+   COMMON_CGI_VARS = frozenset ({
+      "AUTH_TYPE",
+      "CONTENT_LENGTH",
+      "CONTENT_TYPE",
+      "DATE_GMT",
+      "DATE_LOCAL",
+      "DOCUMENT_NAME",
+      "DOCUMENT_ROOT",
+      "DOCUMENT_URI",
+      "GATEWAY_INTERFACE",
+      "LAST_MODIFIED",
+      #"PATH",
+      "PATH_INFO",
+      "PATH_TRANSLATED",
+      "QUERY_STRING",
+      "REMOTE_ADDR",
+      "REMOTE_HOST",
+      "REMOTE_IDENT",
+      "REMOTE_USER",
+      "REQUEST_METHOD",
+      "SCRIPT_NAME",
+      "SERVER_NAME",
+      "SERVER_PORT",
+      "SERVER_PROTOCOL",
+      "SERVER_ROOT",
+      "SERVER_SOFTWARE",
+      "HTTP_ACCEPT",
+      "HTTP_CONNECTION",
+      "HTTP_HOST",
+      "HTTP_PRAGMA",
+      "HTTP_REFERER",
+      "HTTP_USER_AGENT",
+   })
+
+
+   def do_setup_mako ( self ):
+      template_dirs = []
+
+      if 'template' in self.options:
+         dirname, basename = os.path.split (
+            self.options ['template'].rstrip ( os.sep )
+         )
+         assert dirname and basename
+         template_dirs.append ( dirname )
+         self.default_template = basename
+      else:
+         self.default_template = self.script_mode
+      # -- end if
+
+      if self.installed:
+         template_dirs.append (
+            self.config.get_or_fail ( 'INSTALLINFO.libexec' )
+         )
+
+      extra_dirs = self.config.get ( 'STATS.TEMPLATE.root' )
+      if extra_dirs:
+         template_dirs.extend ( extra_dirs )
+
+      if not template_dirs:
+         raise Exception ( "no template directories found!" )
+
+
+      module_dir = self.config.get ( 'STATS.TEMPLATE.module_dir', None )
+      if module_dir is None:
+         module_dir = self.config.get ( 'CACHEDIR.root', None )
+         if module_dir:
+            module_dir += os.sep + 'mako_templates'
+
+
+      self._mako_lookup = mako.lookup.TemplateLookup (
+         directories=template_dirs, module_directory=module_dir,
+         output_encoding=self.TEMPLATE_ENCODING,
+      )
+   # --- end of do_setup_mako (...) ---
+
+   def do_setup ( self ):
+      self.do_setup_parser()
+      script_mode = self.options ['script_mode']
+      assert script_mode and script_mode.islower()
+      if script_mode == 'cgi':
+         cgitb.enable()
+
+      self.do_setup_config()
+      self.template_vars = SelfReferencingDict (
+         roverlay.tools.shenv.setup_env()
+      )
+      roverlay.tools.shenv.restore_msg_vars ( self.template_vars )
+
+      try:
+         del self.template_vars ['STATS_DB']
+      except KeyError:
+         pass
+
+      self.script_mode = script_mode
+      self.outfile     = self.options ['outfile']
+      if self.outfile == '-':
+         self.outfile = None
+
+      self.set_template_vars (
+         EXE=sys.argv[0], EXE_NAME=os.path.basename ( sys.argv[0] ),
+         SCRIPT_MODE=script_mode
+      )
+
+      if script_mode == 'cgi':
+         # inherit cgi-related vars from os.environ
+         self.set_template_vars (
+            roverlay.util.common.keepenv_v (
+               self.NGINX_CGI_VARS|self.COMMON_CGI_VARS
+            ),
+            CGI_FORM=cgi.FieldStorage( keep_blank_values=0 ),
+         )
+
+
+      self.stats_db = None
+      stats_db_file = self.config.get ( 'RRD_DB.file', None )
+      if stats_db_file:
+         self.stats_db = roverlay.db.rrdtool.RRD (
+            stats_db_file, readonly=True
+         )
+         self.stats_db.make_cache()
+
+
+      # transfer db cache to template_vars
+      # * copy lastupdate
+      # * import values
+      #
+      self.set_template_vars (
+         self.stats_db.cache ['values'],
+         lastupdate=self.stats_db.cache ['lastupdate'],
+         STATS_DB=self.stats_db, STATS_DB_FILE=stats_db_file,
+      )
+
+      self.do_setup_mako()
+   # --- end of do_setup (...) ---
+
+   def serve_template ( self, template_name=None, catch_exceptions=True ):
+      try:
+         my_template = self._mako_lookup.get_template (
+            template_name if template_name is not None
+            else self.default_template
+         )
+         ret = my_template.render ( **self.template_vars )
+      except:
+         if catch_exceptions:
+            if self.script_mode == 'cgi':
+               ret = mako.exceptions.html_error_template().render()
+            else:
+               ret = mako.exceptions.text_error_template().render()
+         else:
+            raise
+      # -- end if
+      return ret
+   # --- end of serve_template (...) ---
+
+   def set_template_vars ( self, *args, **kwargs ):
+      for kw in args:
+         self.template_vars.update ( kw )
+      self.template_vars.update ( kwargs )
+   # --- end of setup_vars (...) ---
+
+   def write_cgi_header ( self, stream, encode=False, force=False ):
+      if force or self.script_mode == 'cgi':
+         content_type = self.options ['cgi_content_type']
+         if content_type:
+            header = "Content-Type: {}\n\n".format ( content_type )
+            if encode:
+               stream.write ( header.encode ( self.TEMPLATE_ENCODING ) )
+            else:
+               stream.write ( header )
+            return True
+      return False
+   # --- end of write_cgi_header (...) ---
+
+   @classmethod
+   def encode ( cls, text ):
+      return str ( text ).encode ( cls.TEMPLATE_ENCODING )
+   # --- end of encode (...) ---
+
+   @classmethod
+   def decode ( cls, data, force=False ):
+      if force or not isinstance ( data, str ):
+         return data.decode ( cls.TEMPLATE_ENCODING )
+      else:
+         return str ( data )
+   # --- end of decode (...) ---
+
+# --- end of StatusRuntimeEnvironment ---
+
+
+def main_installed ( *args, **kwargs ):
+   return main ( True, *args, **kwargs )
+# --- end of main_installed (...) ---
+
+def main ( installed, *args, **kw ):
+   main_env = StatusRuntimeEnvironment ( installed, *args, **kw )
+   main_env.setup()
+
+   output_encoded = main_env.serve_template()
+
+   if main_env.outfile:
+      with open (
+         main_env.outfile,
+         'w' + ( 'b' if not isinstance ( output, str ) else 't' )
+      ) as FH:
+         # COULDFIX: write cgi header to file?
+         #main_env.write_cgi_header ( FH, encode=True )
+         FH.write ( output_encoded )
+   else:
+      output = main_env.decode ( output_encoded )
+      main_env.write_cgi_header ( sys.stdout, force=True )
+      sys.stdout.write ( output )
+# --- end of main (...) ---


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

commit:     6ab122cf449017862a26e6da196ce33badfe7ba6
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug 13 08:40:26 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug 13 08:40:26 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6ab122cf

roverlay/argparser: RoverlayStatusArgumentParser

arg parser for the status script.

This commit also modifies the main script's parser (-> defaultscript.main) as
both parser now inherit RoverlayArgumentParser (and not ~Base).

---
 roverlay/argparser.py | 203 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 157 insertions(+), 46 deletions(-)

diff --git a/roverlay/argparser.py b/roverlay/argparser.py
index 054d710..84e1478 100644
--- a/roverlay/argparser.py
+++ b/roverlay/argparser.py
@@ -22,16 +22,32 @@ from roverlay.argutil import \
 
 
 class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
+
+   DESCRIPTION_TEMPLATE = None
+
    def __init__ (
-      self, defaults=None, description=True, formatter_class=True, **kwargs
+      self, defaults=None, description=True, formatter_class=True,
+      format_description=False, **kwargs
    ):
+      if description is True:
+         if self.DESCRIPTION_TEMPLATE is None:
+            desc = (
+               roverlay.core.description_str + '\n'
+               + roverlay.core.license_str
+            )
+         else:
+            desc = self.format_description()
+      elif description:
+         if format_description:
+            desc = self.format_description ( description )
+         else:
+            desc = description
+      else:
+         desc = None
+
       super ( RoverlayArgumentParserBase, self ).__init__ (
-         defaults = defaults,
-         description = (
-            '\n'.join ((
-               roverlay.core.description_str, roverlay.core.license_str
-            )) if description is True else description
-         ),
+         defaults        = defaults,
+         description     = desc,
          formatter_class = (
             argparse.RawDescriptionHelpFormatter
             if formatter_class is True else formatter_class
@@ -43,6 +59,24 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
       self.extra_conf = None
    # --- end of __init__ (...) ---
 
+   def format_description ( self, desc=None ):
+      return ( self.DESCRIPTION_TEMPLATE if desc is None else desc ).format (
+         version=roverlay.core.version,
+         license=roverlay.core.license_str,
+      )
+   # --- end of format_description (...) ---
+
+   def format_command_map ( self, command_map ):
+      return (
+         "\nKnown commands:\n" + '\n'.join (
+            # '* <space> <command> - <command description>'
+            '* {cmd} - {desc}'.format (
+               cmd=cmd.ljust ( 15 ), desc=desc
+            ) for cmd, desc in command_map.items()
+         )
+      )
+   # --- end of format_command_map (...) ---
+
    def do_extraconf ( self, value, path ):
       pos = self.extra_conf
       if isinstance ( path, str ):
@@ -456,7 +490,122 @@ class RoverlayArgumentParserBase ( roverlay.argutil.ArgumentParserProxy ):
 
 # --- end of RoverlayArgumentParserBase ---
 
-class RoverlayMainArgumentParser ( RoverlayArgumentParserBase ):
+class RoverlayArgumentParser ( RoverlayArgumentParserBase ):
+
+   COMMAND_DESCRIPTION = None
+   DEFAULT_COMMAND     = None
+
+   def __init__ ( self, default_command=None, **kwargs ):
+      super ( RoverlayArgumentParser, self ).__init__ ( **kwargs )
+      self.default_command = (
+         self.DEFAULT_COMMAND if default_command is None else default_command
+      )
+      self.command = None
+
+      if self.default_command:
+         assert self.default_command in self.COMMAND_DESCRIPTION
+   # --- end of __init__ (...) ---
+
+   def setup_actions ( self ):
+      arg = self.add_argument_group (
+         "actions", title="actions",
+         description=self.format_command_map ( self.COMMAND_DESCRIPTION ),
+      )
+
+      arg (
+         'command', default=self.default_command, metavar='<action>',
+         nargs="?", choices=self.COMMAND_DESCRIPTION.keys(),
+         flags=self.ARG_HELP_DEFAULT,
+         help="action to perform"
+      )
+
+      return arg
+   # --- end of setup_actions (...) ---
+
+   def parse_actions ( self ):
+      command = self.parsed ['command']
+   # --- end of parse_actions (...) ---
+
+# --- end of RoverlayArgumentParser ---
+
+class RoverlayStatusArgumentParser ( RoverlayArgumentParser ):
+
+   DESCRIPTION_TEMPLATE = "roverlay status tool {version}\n{license}"
+
+   SETUP_TARGETS = (
+      'version',
+      'output_options', 'script_mode', 'config_minimal',
+      'actions',
+   )
+   PARSE_TARGETS = ( 'config', 'actions', 'extra', )
+
+   COMMAND_DESCRIPTION = {
+      'status': 'report overlay status',
+   }
+   DEFAULT_COMMAND = 'status'
+
+   MODES = frozenset ({ 'cgi', 'cli' })
+   DEFAULT_MODE = 'cli'
+
+   def setup_script_mode ( self ):
+      arg = self.add_argument_group (
+         "script_mode", title="script mode",
+      )
+
+      arg (
+         '-m', '--mode', dest='script_mode',
+         default=self.DEFAULT_MODE, metavar='<mode>',
+         flags=self.ARG_WITH_DEFAULT, choices=self.MODES,
+         help='set script mode (%(choices)s)',
+      )
+
+      for script_mode in self.MODES:
+         arg (
+            '--' + script_mode, dest='script_mode',
+            flags=self.ARG_SHARED, action='store_const', const=script_mode,
+            help='set script mode to {!r}'.format ( script_mode ),
+         )
+
+      return arg
+   # --- end of setup_script_mode (...) ---
+
+   def setup_output_options ( self ):
+      arg = self.add_argument_group (
+         'output_options', title='output options',
+      )
+
+      arg (
+         '-O', '--output', dest='outfile', default='-',
+         flags=self.ARG_WITH_DEFAULT|self.ARG_META_FILE,
+         type=couldbe_stdout_or_file,
+         help='output file (or stdout)',
+      )
+
+      arg (
+         '-t', '--template', dest='template', default=argparse.SUPPRESS,
+         flags=self.ARG_WITH_DEFAULT|self.ARG_META_FILE,
+         type=is_fs_file,
+         help='template file for generating output',
+      )
+
+      arg (
+         '--cgi-content-type', dest='cgi_content_type', default="text/html",
+         flags=self.ARG_WITH_DEFAULT, metavar='<type>',
+         help='cgi content type',
+      )
+
+      return arg
+   # --- end of setup_output_options (...) ---
+
+   def parse_extra ( self ):
+      self.parsed ['want_logging']   = False
+      self.parsed ['load_main_only'] = True
+   # --- end of parse_extra (...) ---
+
+
+# --- end of RoverlayStatusArgumentParser (...) ---
+
+class RoverlayMainArgumentParser ( RoverlayArgumentParser ):
 
    SETUP_TARGETS = (
       'version', 'actions', 'config', 'overlay', 'remote',
@@ -485,21 +634,6 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParserBase ):
 
    DEFAULT_COMMAND = 'create'
 
-   def __init__ ( self, default_command=None, command_desc=None,**kwargs ):
-      super ( RoverlayMainArgumentParser, self ).__init__ ( **kwargs )
-
-      self.default_command = (
-         self.DEFAULT_COMMAND if default_command is None else default_command
-      )
-      self.command_desc = (
-         self.COMMAND_DESCRIPTION if command_desc is None else command_desc
-      )
-
-      self.command = None
-
-      assert self.default_command in self.command_desc
-   # --- end of __init__ (...) ---
-
    def parse_actions ( self ):
       command = self.parsed ['command']
 
@@ -522,29 +656,6 @@ class RoverlayMainArgumentParser ( RoverlayArgumentParserBase ):
       self.command = command
    # --- end of parse_actions (...) ---
 
-   def setup_actions ( self ):
-      arg = self.add_argument_group (
-         "actions", title="actions",
-         description=(
-            "\nKnown commands:\n" + '\n'.join (
-               # '* <space> <command> - <command description>'
-               '* {cmd} - {desc}'.format (
-                  cmd=cmd.ljust ( 15 ), desc=desc
-               ) for cmd, desc in self.command_desc.items()
-            )
-         )
-      )
-
-      arg (
-         'command', default=self.default_command, metavar='<action>',
-         nargs="?", choices=self.command_desc.keys(),
-         flags=self.ARG_HELP_DEFAULT,
-         help="action to perform"
-      )
-
-      return arg
-   # --- end of setup_actions (...) ---
-
    def setup_setupdirs ( self ):
       arg = self.add_argument_group (
          'setupdirs', title='setupdirs options',


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

commit:     5895b5e0763ebf9b52dedf2a5760bc4791ad1c1d
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Aug 12 08:25:49 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Aug 12 08:28:25 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5895b5e0

setupdirs command: don't modify symlinks

---
 roverlay/defaultscript.py | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 0aa32d8..dfbe29d 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -170,12 +170,18 @@ def run_setupdirs ( env ):
             )
 
             if dirpath:
-               dodir ( dirpath )
-               if dirmask & WANT_PRIVATE:
-                  os.chmod ( dirpath, dirmode_private )
-               if dirmask & WANT_USERDIR and should_chown:
-                  os.chown ( dirpath, target_uid, target_gid )
-
+               if os.path.islink ( dirpath ):
+                  sys.stdout.write (
+                     '{!r} is a symlink - skipping setupdir '
+                     'actions.\n'.format ( dirpath )
+                  )
+               else:
+                  #elif dodir ( dirpath ):
+                  dodir ( dirpath )
+                  if dirmask & WANT_PRIVATE:
+                     os.chmod ( dirpath, dirmode_private )
+                  if dirmask & WANT_USERDIR and should_chown:
+                     os.chown ( dirpath, target_uid, target_gid )
 
    return os.EX_OK
 # --- end of run_setupdirs (...) ---


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

commit:     4d16ea3712b1694bed4f6bbbca84ef90095631cf
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Aug 12 08:15:39 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Aug 12 08:15:39 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4d16ea37

roverlay: do not fail if rrdtool is missing

If rrdtool is missing: disable persistent stats collection and continue.

Additionally, database setup/writing has been moved to RuntimeEnvironment.

---
 roverlay/defaultscript.py | 12 +++--------
 roverlay/runtime.py       | 54 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/roverlay/defaultscript.py b/roverlay/defaultscript.py
index 9d00e94..0aa32d8 100644
--- a/roverlay/defaultscript.py
+++ b/roverlay/defaultscript.py
@@ -60,6 +60,7 @@ def main ( installed, *args, **kw ):
 
    else:
       roverlay.hook.setup()
+      main_env.setup_database()
 
       retcode = os.EX_OK
 
@@ -70,15 +71,8 @@ def main ( installed, *args, **kw ):
       else:
          die ( "unknown command: {!r}".format ( main_env.command ) )
 
-      if main_env.stats_db_file and main_env.want_db_commit:
-         main_env.stats.write_database()
-         roverlay.hook.run ( 'db_written' )
-
-      if main_env.options ['dump_stats']:
-         print ( "\n{:-^60}".format ( " stats dump " ) )
-         print ( main_env.stats )
-         print ( "{:-^60}".format ( " end stats dump " ) )
-
+      main_env.write_database()
+      main_env.dump_stats()
       sys.exit ( retcode )
 # --- end of main (...) ---
 

diff --git a/roverlay/runtime.py b/roverlay/runtime.py
index f44dbad..81a7726 100644
--- a/roverlay/runtime.py
+++ b/roverlay/runtime.py
@@ -4,9 +4,12 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
+import logging
+import errno
 import os
 import sys
 
+
 import roverlay.argparser
 import roverlay.core
 import roverlay.hook
@@ -24,6 +27,7 @@ class RuntimeEnvironment ( object ):
    ):
       super ( RuntimeEnvironment, self ).__init__()
 
+      self.logger            = logging.getLogger()
       self.HLINE             = 79 * '-'
       self.stats             = roverlay.stats.collector.static
       self.config            = None
@@ -109,10 +113,7 @@ class RuntimeEnvironment ( object ):
             raise
 
 
-      self.stats_db_file  = self.config.get ( 'RRD_DB.file', None )
-      if self.stats_db_file:
-         self.stats.setup_database ( self.config )
-
+      self.stats_db_file     = self.config.get ( 'RRD_DB.file', None )
       self.command           = command
       self.options           = options
       self.additional_config = additional_config
@@ -125,6 +126,51 @@ class RuntimeEnvironment ( object ):
       self.stats.time.end ( "setup" )
    # --- end of setup (...) ---
 
+   def setup_database ( self ):
+      if self.stats_db_file:
+         try:
+            self.stats.setup_database ( self.config )
+
+         except OSError as oserr:
+            if oserr.errno == errno.ENOENT:
+               self.stats_db_file = None
+               self.logger.error (
+                  'rrdtool not available. '
+                  'Persistent stats collection has been disabled.'
+               )
+               return False
+            else:
+               raise
+
+         else:
+            return True
+      else:
+         return False
+   # --- end of setup_database (...) ---
+
+   def write_database ( self, hook_event=True ):
+      if self.stats_db_file and self.want_db_commit:
+         self.stats.write_database()
+         if hook_event:
+            roverlay.hook.run ( "db_written" )
+         return True
+      else:
+         return False
+   # --- end of write_database (...) ---
+
+   def dump_stats ( self, stream=None, force=False ):
+      if force or self.options ['dump_stats']:
+         cout = sys.stdout.write if stream is None else stream.write
+
+         cout ( "\n{:-^60}\n".format ( " stats dump " ) )
+         cout ( str ( self.stats ) )
+         cout ( "\n{:-^60}\n".format ( " end stats dump " ) )
+
+         return True
+      else:
+         return False
+   # --- end of dump_stats (...) ---
+
    def set_action_done ( self, action ):
       self.actions_done.add ( action )
    # --- end of set_action_done (...) ---


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

commit:     1feee9c63998b09147f9de18c4e39c5f97f8e067
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug  7 15:40:56 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug  7 15:40:56 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1feee9c6

roverlay: --strict[-sync]

--strict-sync: exit (call die()) if sync doesn't succeed
--strict: enable all --strict- switches

---
 roverlay/argutil.py | 16 ++++++++++++++++
 roverlay/main.py    |  8 +++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 0f0b593..13f23df 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -331,6 +331,20 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
    )
 
    arg (
+      '--strict',
+      help='enable all --strict-<sth> options',
+      default=False,
+      action='store_true',
+   )
+
+   arg (
+      '--strict-sync',
+      help='exit on any sync errors',
+      default=False,
+      action='store_true',
+   )
+
+   arg (
       '--nosync', '--no-sync', default=argparse.SUPPRESS,
       help="disable syncing with remotes (offline mode).",
       action='store_true',
@@ -510,6 +524,8 @@ def parse_argv ( command_map, **kw ):
       target_gid              = p.target_gid,
       dump_stats              = p.dump_stats,
       sync_imported           = p.sync_imported,
+      strict                  = p.strict,
+      strict_sync             = p.strict_sync,
    )
 
 

diff --git a/roverlay/main.py b/roverlay/main.py
index 4954645..4a65aee 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -120,6 +120,9 @@ def main (
 
    def run_sync():
       if "sync" in actions_done: return
+
+      STRICT_SYNC = OPTION ( 'strict' ) or OPTION ( 'strict_sync' )
+
       try:
          # set up the repo list
          global repo_list
@@ -136,7 +139,7 @@ def main (
             repo_list.load()
 
          ## this runs _nosync() or _sync(), depending on extra_opts->nosync
-         repo_list.sync()
+         sync_success = repo_list.sync ( fail_greedy=STRICT_SYNC )
          set_action_done ( "sync" )
 
       except KeyboardInterrupt:
@@ -149,6 +152,9 @@ def main (
             )
          else:
             raise
+      else:
+         if not sync_success and STRICT_SYNC:
+            die ( "errors occured while syncing.", DIE.SYNC )
    # --- end of run_sync() ---
 
    def run_apply_package_rules():


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

commit:     fa34e37bc4e28f54e4a952331063e9b02b8f5fcc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug  2 14:27:10 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug  2 14:27:10 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=fa34e37b

roverlay/hook: set initial directory

run(): set initial working directory depending on phase

---
 roverlay/hook.py | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/roverlay/hook.py b/roverlay/hook.py
index 262d3c2..d89eca0 100644
--- a/roverlay/hook.py
+++ b/roverlay/hook.py
@@ -4,7 +4,7 @@
 # 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.path
+import os
 import logging
 
 import roverlay.config
@@ -29,6 +29,10 @@ _EVENT_RESTRICT = None
 _EVENT_POLICY = 0
 
 
+PHASE_INITIAL_DIRS = {
+   'user': True,
+}
+
 class HookException ( Exception ):
    pass
 
@@ -184,9 +188,13 @@ def run ( phase, catch_failure=True ):
    # -- end if
 
 
-   if _EVENT_SCRIPT and phase_allowed ( phase ):
+   if _EVENT_SCRIPT and phase_allowed ( phase.lower() ):
+      initial_dir = PHASE_INITIAL_DIRS.get ( phase.lower() )
+      if initial_dir is True:
+         initial_dir = os.getcwd()
+
       if roverlay.tools.shenv.run_script (
-         _EVENT_SCRIPT, phase, return_success=True
+         _EVENT_SCRIPT, phase, return_success=True, initial_dir=initial_dir,
       ):
          return True
       elif catch_failure:


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

commit:     6efa8bdd1923b472dab2895823ab975009a94d2f
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug  2 10:21:49 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug  2 10:21:49 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6efa8bdd

roverlay/argutil: --sync-imports

--sync-imports: fetch src when importing ebuilds even if --nosync is given

---
 roverlay/argutil.py | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 1f9a0bf..0f0b593 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -337,6 +337,16 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
    )
 
    arg (
+      '--sync-imports',
+      default=None, dest='sync_imported',
+      help=(
+         'allow fetching src files for imported ebuilds even if sync '
+         'is forbidden'
+      ),
+      action='store_true',
+   )
+
+   arg (
       '--force-distroot',
       help="always use <DISTROOT>/<repo name> as repo distdir.",
       **opt_in
@@ -499,6 +509,7 @@ def parse_argv ( command_map, **kw ):
       target_uid              = p.target_uid,
       target_gid              = p.target_gid,
       dump_stats              = p.dump_stats,
+      sync_imported           = p.sync_imported,
    )
 
 


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

commit:     43ab1d2328ee2968dc0d5076f33629f859e12718
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug  2 10:17:52 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug  2 10:17:52 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=43ab1d23

support suffixes $PV when importing ebuilds

Selfdep validation may fail/ignore when dealing with import ebuilds with a
version suffix ("_pre..." etc.).

---
 roverlay/packageinfo.py  | 18 +++++++++++-------
 roverlay/versiontuple.py | 30 +++++++++++++++++++++++++++---
 2 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 752f996..704807e 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -805,17 +805,21 @@ class PackageInfo ( object ):
       pv_str, DONT_CARE, pr_str    = pvr.partition    ( '-r' )
       pv,     DONT_CARE, pv_suffix = pv_str.partition ( '_'  )
 
+      # non-digit chars in pv are not supported
+      pv_list = [ int(z) for z in pv.split ( '.' ) ]
+
       if pv_suffix:
          # not supported
-         raise NotImplementedError (
-            "version suffix {!r} cannot be preserved for $PVR {!r}".format (
-               pv_suffix, pvr
+         self._info ['version'] = (
+            roverlay.versiontuple.SuffixedIntVersionTuple (
+               pv_list, pv_suffix
             )
          )
-      # non-digit chars in pv are unsupported, too
-      self._info ['version'] = roverlay.versiontuple.IntVersionTuple (
-         int ( z ) for z in pv.split ( '.' )
-      )
+      else:
+         self._info ['version'] = (
+            roverlay.versiontuple.IntVersionTuple ( pv_list )
+         )
+
       self._info ['rev'] = int ( pr_str ) if pr_str else 0
 
       self._info ['ebuild_verstr'] = pvr

diff --git a/roverlay/versiontuple.py b/roverlay/versiontuple.py
index 6586088..579471f 100644
--- a/roverlay/versiontuple.py
+++ b/roverlay/versiontuple.py
@@ -67,9 +67,9 @@ def pkgver_decorator ( func ):
 
 class VersionTuple ( tuple ):
 
-   def __init__ ( self, *args, **kwargs ):
-      super ( VersionTuple, self ).__init__ ( *args, **kwargs )
-   # --- end of __init__ (...) ---
+   def __new__ ( cls, gen_tuple, *args, **kwargs ):
+      return super ( VersionTuple, cls ).__new__ ( cls, gen_tuple )
+   # --- end of __new__ (...) ---
 
    def get_comparator ( self, mode ):
       """Returns a function "this ~ other" that returns
@@ -228,4 +228,28 @@ class IntVersionTuple ( VersionTuple ):
          return NotImplemented
    # --- end of __gt__ (...) ---
 
+   def __str__ ( self ):
+      return '.'.join ( str(k) for k in self )
+   # --- end of __str__ ( self )
+
 # --- end of IntVersionTuple ---
+
+class SuffixedIntVersionTuple ( VersionTuple ):
+   # inherit VersionTuple: does not implement comparision functions
+
+   def __init__ ( self, gen_tuple, suffix ):
+      super ( SuffixedIntVersionTuple, self ).__init__ ( gen_tuple )
+      self.suffix = suffix
+   # --- end of __init__ (...) ---
+
+   def get_suffix_str ( self ):
+      ret = str ( self.suffix )
+      if not ret or ret[0] == '_':
+         return ret
+      else:
+         return '_' + ret
+   # --- end of get_suffix_str (...) ---
+
+   def __str__ ( self ):
+      return '.'.join ( str(k) for k in self ) + self.get_suffix_str()
+   # --- end of __str__ (...) ----


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

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

roverlay/packageinfo: bind hashdict in __init__()

---
 roverlay/packageinfo.py | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 25e67d9..752f996 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -134,6 +134,8 @@ class PackageInfo ( object ):
       # self.selfdeps is a list of _mandatory_ selfdeps
       self.selfdeps = None
 
+      self.hashdict = dict()
+
       #self.selfdeps_valid      = UNDEF
       #self.overlay_package_ref = None
       #self._evars              = dict()
@@ -537,17 +539,18 @@ class PackageInfo ( object ):
       """
       pkgfile = self.get ( "package_file" )
 
-      if hasattr ( self, 'hashdict' ) and self.hashdict:
+      if self.hashdict:
          new_hashes = (
             frozenset ( hashlist ) - frozenset ( self.hashdict.keys() )
          )
-
-         if new_hashes:
-            self.hashdict.update (
-               roverlay.digest.multihash_file ( pkgfile, new_hashes )
-            )
       else:
-         self.hashdict = roverlay.digest.multihash_file ( pkgfile, hashlist )
+         new_hashes = hashlist
+
+
+      if new_hashes:
+         self.hashdict.update (
+            roverlay.digest.multihash_file ( pkgfile, new_hashes )
+         )
 
       return self.hashdict
    # --- end of make_hashes (...) ---


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

commit:     29ed894fc47817f4a67c90af6c1fe664d6c95dc0
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug  1 12:26:22 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug  1 12:26:22 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=29ed894f

roverlay: disable revbump check via --no-revbump

The revbump-on-tarball-change check when doing incremental overlay creation
takes some time. The --no-revbump switch allows to disable it.

---
 roverlay/argutil.py | 9 +++++++++
 roverlay/main.py    | 5 ++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index b101169..1f9a0bf 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -389,6 +389,14 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
    )
 
    arg (
+      '--no-revbump',
+      help="disable revbump-on-tarball change (saves time)",
+      dest='revbump',
+      default=True,
+      action='store_false',
+   )
+
+   arg (
       '--dump-file',
       help='''
          standard file or stdout target for dumping information
@@ -483,6 +491,7 @@ def parse_argv ( command_map, **kw ):
       force_distroot          = p.force_distroot,
       skip_manifest           = p.no_manifest,
       incremental             = p.incremental,
+      revbump                 = p.revbump,
       immediate_ebuild_writes = p.immediate_ebuild_writes,
       dump_file               = p.dump_file,
       fixup_category_move     = p.fixup_category_move,

diff --git a/roverlay/main.py b/roverlay/main.py
index 7830d23..dff81a8 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -292,7 +292,10 @@ def main (
          )
 
          repo_list.add_packages ( overlay_creator.add_package )
-         overlay_creator.enqueue_postponed()
+         if OPTION ( 'revbump' ):
+            overlay_creator.enqueue_postponed()
+         else:
+            overlay_creator.discard_postponed()
 
          overlay_creator.release_package_rules()
 


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

commit:     3dae409f5f64cb96e095d9759b08cd9cf7e5fc48
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 29 14:55:58 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 29 14:55:58 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=3dae409f

roverlay/main: optionally write stats db file

---
 roverlay/main.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/roverlay/main.py b/roverlay/main.py
index 80a6813..04678fa 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -620,6 +620,12 @@ def main (
       # initialize roverlay.hook
       roverlay.hook.setup()
 
+      # initialize database
+      STATS_DB_FILE = conf.get ( 'RRD_DB.file', None )
+      if STATS_DB_FILE:
+         roverlay.stats.collector.static.setup_database ( conf )
+         want_db_commit = False
+
       # always run sync 'cause commands = {create,sync,apply_rules}
       # and create,apply_rules implies (no)sync
       run_sync()
@@ -629,6 +635,12 @@ def main (
          run_apply_package_rules()
       elif 'create' in actions:
          run_overlay_create()
+         want_db_commit = True
+
+
+      if STATS_DB_FILE and want_db_commit:
+         roverlay.stats.collector.static.write_db()
+         roverlay.hook.run ( 'db_written' )
 
 
       # *** TEMPORARY ***


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-07-29  8:55 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-07-29  8:55 UTC (permalink / raw
  To: gentoo-commits

commit:     563e9dba634c7a1525055476019168fb7f541139
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 29 08:55:06 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 29 08:55:06 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=563e9dba

roverlay/main: print formatted stats str

---
 roverlay/argutil.py |  8 ++++++++
 roverlay/main.py    | 15 +++++++++++----
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 449b359..04ea84f 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -322,6 +322,13 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
    )
 
    arg (
+      '--dump-stats',
+      help='print all stats to stdout (raw format)',
+      default=False,
+      action='store_true',
+   )
+
+   arg (
       '--nosync', '--no-sync', default=argparse.SUPPRESS,
       help="disable syncing with remotes (offline mode).",
       action='store_true',
@@ -480,6 +487,7 @@ def parse_argv ( command_map, **kw ):
       fixup_category_move_rev = p.fixup_category_move_rev,
       target_uid              = p.target_uid,
       target_gid              = p.target_gid,
+      dump_stats              = p.dump_stats,
    )
 
 

diff --git a/roverlay/main.py b/roverlay/main.py
index cc3a5ab..80a6813 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -385,7 +385,12 @@ def main (
          optionally ( overlay_creator.write_overlay, 'write_overlay' )
          optionally ( overlay_creator.show_overlay,  'show_overlay'  )
          if OPTION ( 'print_stats' ):
-            print ( "\n***old stats are disabled (--stats)***" )
+            sys.stdout.write ( '\n' )
+            sys.stdout.write (
+               roverlay.stats.collector.static.get_creation_str()
+            )
+            sys.stdout.write ( '\n\n' )
+            sys.stdout.flush()
 
 
          # FIXME/TODO:
@@ -627,9 +632,11 @@ def main (
 
 
       # *** TEMPORARY ***
-      print ( "\n{:-^60}".format ( " stats dump " ) )
-      print ( roverlay.stats.collector.static )
-      print ( "{:-^60}".format ( " end stats dump " ) )
+      if OPTION ( 'dump_stats' ):
+         print ( "\n{:-^60}".format ( " stats dump " ) )
+         print ( roverlay.stats.collector.static )
+         print ( "{:-^60}".format ( " end stats dump " ) )
+      # *** END TEMPORARY ***
 
 
    if len ( actions ) > len ( actions_done ):


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

commit:     638280bfa2dd4a10c99a8c6a3deac8ef9ba63ef4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 26 13:00:19 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 26 13:00:19 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=638280bf

roverlay/main: use/show new stats

temporary change
* stats need to be persistent (write them to file/db)
* stats need proper str() 'visualization'

---
 roverlay/main.py | 39 +++++++++++++++++----------------------
 1 file changed, 17 insertions(+), 22 deletions(-)

diff --git a/roverlay/main.py b/roverlay/main.py
index b97b5cd..cc3a5ab 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -10,10 +10,10 @@ __all__ = [ 'main' ]
 
 import os
 import sys
-import time
 
 import roverlay
 import roverlay.tools.shenv
+import roverlay.stats.collector
 
 # roverlay modules will be imported later
 
@@ -214,22 +214,17 @@ def main (
             repo_list.load()
 
          ## this runs _nosync() or _sync(), depending on extra_opts->nosync
-         t_start = time.time()
          repo_list.sync()
-         global sync_time
-         sync_time = time.time() - t_start
-
          set_action_done ( "sync" )
 
       except KeyboardInterrupt:
          die ( "Interrupted", DIE.INTERRUPT )
       except:
          if HIDE_EXCEPTIONS:
-               die (
-                  "nosync() failed!" if OPTION ( "nosync" ) \
-                     else "sync() failed!",
-                  DIE.SYNC
-               )
+            die (
+               ( "no" if OPTION ( "nosync" ) else "" ) + "sync() failed!",
+               DIE.SYNC
+            )
          else:
             raise
    # --- end of run_sync() ---
@@ -338,20 +333,18 @@ def main (
             FH_SHARED = False
             FH = open ( dump_file, 'wt' )
 
-         time_start = time.time()
          repo_list.add_packages ( receive_package_counting )
-         time_add_packages = time.time() - time_start
 
          if modify_counter [0] > 0:
             FH.write ( "\n" )
 
          #FH.write (
          sys.stdout.write (
-            'done after {t} seconds\n'
+            'done after {t:.2f} seconds\n'
             '{p} packages processed in total, out of which\n'
             '{m} have been modified and '
             '{n} have been filtered out\n'.format (
-               t = round ( time_add_packages, 1 ),
+               t = roverlay.stats.collector.static.repo.queue_time.get_total(),
                p = sum ( modify_counter ),
                m = modify_counter [0],
                n = modify_counter [2],
@@ -376,14 +369,7 @@ def main (
             immediate_ebuild_writes = OPTION ( 'immediate_ebuild_writes' ),
          )
 
-         if 'sync_time' in globals():
-            overlay_creator.set_timestats ( 'sync_packages', sync_time )
-
-         t_start = time.time()
          repo_list.add_packages ( overlay_creator.add_package )
-         overlay_creator.set_timestats (
-            'add_packages', time.time() - t_start
-         )
 
          overlay_creator.release_package_rules()
 
@@ -399,7 +385,7 @@ def main (
          optionally ( overlay_creator.write_overlay, 'write_overlay' )
          optionally ( overlay_creator.show_overlay,  'show_overlay'  )
          if OPTION ( 'print_stats' ):
-            print ( "\n" + overlay_creator.stats_str() )
+            print ( "\n***old stats are disabled (--stats)***" )
 
 
          # FIXME/TODO:
@@ -508,6 +494,7 @@ def main (
          raise
 
    try:
+      roverlay.stats.collector.static.time.begin ( "setup" )
       roverlay.setup_initial_logger()
 
       conf = roverlay.load_config_file (
@@ -527,6 +514,8 @@ def main (
          )
       else:
          raise
+   else:
+      roverlay.stats.collector.static.time.end ( "setup" )
 
    if do_setupdirs:
       sys.exit ( run_setupdirs (
@@ -637,6 +626,12 @@ def main (
          run_overlay_create()
 
 
+      # *** TEMPORARY ***
+      print ( "\n{:-^60}".format ( " stats dump " ) )
+      print ( roverlay.stats.collector.static )
+      print ( "{:-^60}".format ( " end stats dump " ) )
+
+
    if len ( actions ) > len ( actions_done ):
       die (
          "Some actions (out of {!r}) could not be performed!".format (


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-07-23  7:51 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-07-23  7:51 UTC (permalink / raw
  To: gentoo-commits

commit:     80a5617c256f0c650221849a5f0c0d39b3cb2686
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 22 12:08:45 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 22 12:08:45 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=80a5617c

roverlay/argutil: remove --run-script entirely

---
 roverlay/argutil.py | 20 --------------------
 1 file changed, 20 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index df40d34..449b359 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -6,8 +6,6 @@
 
 """provides arg parsing for the roverlay main script"""
 
-# TODO: remove --run-script here
-
 __all__ = [ 'parse_argv', ]
 
 import os
@@ -409,18 +407,6 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
       type=is_gid,
    )
 
-   arg (
-      '--run-script', '-X', default=argparse.SUPPRESS,
-      metavar="<script>",
-      help="run a script in roverlay\'s environment and exit afterwards",
-      type=is_fs_file,
-   )
-
-   arg (
-      '--script-args', dest='run_script_args', default=argparse.SUPPRESS,
-      metavar="<args>",
-      help="args for --run-script",
-   )
 
 #   # TODO
 #   arg (
@@ -496,12 +482,6 @@ def parse_argv ( command_map, **kw ):
       target_gid              = p.target_gid,
    )
 
-   if given ( 'run_script' ):
-      extra ['run_script']      = p.run_script
-      extra ['run_script_args'] = tuple (
-         getattr ( p, 'run_script_args', "" ).split ( None )
-      )
-      # or use shlex for splitting
 
    if given ( 'overlay' ):
       doconf ( p.overlay, 'OVERLAY.dir' )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-07-23  7:51 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-07-23  7:51 UTC (permalink / raw
  To: gentoo-commits

commit:     09b615d1352bab7662426b3b5c64bb60ae4e4a7b
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 17:45:47 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 17:45:47 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=09b615d1

roverlay/strutil: unquote_all()

---
 roverlay/strutil.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index b4e2631..755a191 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -108,7 +108,7 @@ def pipe_lines ( _pipe, use_filter=False, filter_func=None ):
       return lines
 # --- end of pipe_lines (...) ---
 
-def unquote ( _str, keep_going=False):
+def unquote ( _str, keep_going=False ):
    """Removes enclosing quotes from a string.
 
    arguments:
@@ -124,6 +124,10 @@ def unquote ( _str, keep_going=False):
    return _str
 # --- end of unquote (...) ---
 
+def unquote_all ( s ):
+   return unquote ( s, keep_going=True )
+# --- end of unquote_all (...) ---
+
 def bytes_try_decode (
    byte_str,
    encodings=_DEFAULT_ENCODINGS,


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-07-19 18:00 André Erdmann
  2013-07-23  7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-07-19 18:00 UTC (permalink / raw
  To: gentoo-commits

commit:     545daa132cf9ea6e52e925c57b3a3718e2916ad1
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 18:00:12 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 18:00:12 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=545daa13

roverlay/main: use new depres console

---
 roverlay/main.py | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/roverlay/main.py b/roverlay/main.py
index 31a5ea0..b97b5cd 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -579,10 +579,15 @@ def main (
          die ( "depres_console cannot be run with other commands!", DIE.USAGE )
 
       try:
-         from roverlay.depres.simpledeprule.console import DepResConsole
-         con = DepResConsole()
-         con.run()
-         set_action_done ( "depres_console" )
+         from roverlay.console.depres import DepresConsole
+         con = DepresConsole()
+         con.setup ( config=conf )
+         try:
+            con.run_forever()
+            set_action_done ( "depres_console" )
+         finally:
+            con.close()
+
       except ImportError:
          if HIDE_EXCEPTIONS:
             die ( "Cannot import depres console!", DIE.IMPORT )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-07-17 18:05 André Erdmann
  2013-07-17 18:05 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-07-17 18:05 UTC (permalink / raw
  To: gentoo-commits

commit:     a01c5b354610331bdd684aa3632a1f692a44d6cb
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jul 17 17:58:11 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jul 17 18:00:00 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a01c5b35

fix versiontuple (again)

The le/lt/ge/gt comparision functions were completely wrong, which caused
selfdep validation to misbehave. Checking "(0,97) <= (1,1,2)" always returned
False (but 0 < 1!), whereas "(1,1,2) >= (0,97)" returned False, too (which is
be correct, but "neither less nor greater nor equal" makes no sense at all).

In a second (incremental) run, all comparisions would then evaluate to true,
because PackageInfo created normal tuples for scanned ebuilds, for which
IntVersionTuple returns NotImplemented (when comparing).
And bool( NotImplemented ) <=> True,
so even IntVersionTuple(1,1) was "less than" tuple(0,0).

This commit fixes this issue.

---
 roverlay/packageinfo.py  |  9 +++++----
 roverlay/versiontuple.py | 52 +++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 0224d6c..feee360 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -108,7 +108,7 @@ class PackageInfo ( object ):
       'has_suggests',
    ))
    _UPDATE_KEYS_SIMPLE_INITIAL = frozenset ((
-      'package_filename',
+      'package_filename', 'name',
    ))
    _UPDATE_KEYS_FILTER_NONE    = frozenset ((
       'src_uri_base',
@@ -810,9 +810,10 @@ class PackageInfo ( object ):
             )
          )
       # non-digit chars in pv are unsupported, too
-
-      self._info ['version'] = tuple ( int ( z ) for z in pv.split ( '.' ) )
-      self._info ['rev']     =  int ( pr_str ) if pr_str else 0
+      self._info ['version'] = roverlay.versiontuple.IntVersionTuple (
+         int ( z ) for z in pv.split ( '.' )
+      )
+      self._info ['rev'] = int ( pr_str ) if pr_str else 0
 
       self._info ['ebuild_verstr'] = pvr
    # --- end of _use_pvr (...) ---

diff --git a/roverlay/versiontuple.py b/roverlay/versiontuple.py
index 0ca902a..20d5cf8 100644
--- a/roverlay/versiontuple.py
+++ b/roverlay/versiontuple.py
@@ -166,36 +166,64 @@ class IntVersionTuple ( VersionTuple ):
 
    def __le__ ( self, other ):
       if isinstance ( other, self.__class__ ):
-         return all ( a <= b
-            for a, b in _zip_longest ( self, other, fillvalue=0 )
-         )
+         #
+         # ( k0, k1, ..., kN ) x ( l0, l1, ..., lN )
+         #
+         # from left to right (high to low)
+         # if k_j < l_j
+         #    return True (k <= j)
+         # elif k_j == l_j
+         #    continue with next
+         # else
+         #    return False (k > j)
+         #
+         # return True if last pair was equal
+         for a, b in _zip_longest ( self, other, fillvalue=0 ):
+            if a < b:
+               return True
+            elif a > b:
+               return False
+         else:
+            return True
       else:
          return NotImplemented
    # --- end of __le__ (...) ---
 
    def __ge__ ( self, other ):
       if isinstance ( other, self.__class__ ):
-         return all ( a >= b
-            for a, b in _zip_longest ( self, other, fillvalue=0 )
-         )
+         for a, b in _zip_longest ( self, other, fillvalue=0 ):
+            if a > b:
+               return True
+            elif a < b:
+               return False
+         else:
+            return True
       else:
          return NotImplemented
    # --- end of __ge__ (...) ---
 
    def __lt__ ( self, other ):
       if isinstance ( other, self.__class__ ):
-         return all ( a < b
-            for a, b in _zip_longest ( self, other, fillvalue=0 )
-         )
+         for a, b in _zip_longest ( self, other, fillvalue=0 ):
+            if a < b:
+               return True
+            elif a > b:
+               return False
+         else:
+            return False
       else:
          return NotImplemented
    # --- end of __lt__ (...) ---
 
    def __gt__ ( self, other ):
       if isinstance ( other, self.__class__ ):
-         return all ( a > b
-            for a, b in _zip_longest ( self, other, fillvalue=0 )
-         )
+         for a, b in _zip_longest ( self, other, fillvalue=0 ):
+            if a > b:
+               return True
+            elif a < b:
+               return False
+         else:
+            return False
       else:
          return NotImplemented
    # --- end of __gt__ (...) ---


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-07-15 22:31 André Erdmann
  2013-07-16 16:36 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-07-15 22:31 UTC (permalink / raw
  To: gentoo-commits

commit:     6e32f77915e8bf388059f79750a5a30bf8d2fb49
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 15 22:29:05 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 15 22:29:05 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6e32f779

--run-script: respect EvENT_HOOK_RESTRICT

---
 roverlay/hook.py |  4 ++--
 roverlay/main.py | 25 +++++++++++++++----------
 2 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/roverlay/hook.py b/roverlay/hook.py
index e56aa33..262d3c2 100644
--- a/roverlay/hook.py
+++ b/roverlay/hook.py
@@ -32,12 +32,12 @@ _EVENT_POLICY = 0
 class HookException ( Exception ):
    pass
 
-def setup():
+def setup ( force=False ):
    global _EVENT_SCRIPT
    global _EVENT_POLICY
    global _EVENT_RESTRICT
 
-   if roverlay.config.get ( 'write_disabled', False ):
+   if roverlay.config.get ( 'write_disabled', False ) and not force:
       _EVENT_SCRIPT = False
       return
 

diff --git a/roverlay/main.py b/roverlay/main.py
index 24c02c6..7a88171 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -497,16 +497,21 @@ def main (
 
    if do_runscript:
       import roverlay.tools.shenv
-      sys.exit (
-         roverlay.tools.shenv.run_script (
-            script         = extra_opts ['run_script'],
-            phase          = "user",
-            argv           = extra_opts ['run_script_args'],
-            return_success = False,
-            log_output     = False,
-            initial_dir    = os.getcwd(),
-         ).returncode
-      )
+      import roverlay.hook
+      roverlay.hook.setup ( force=True )
+      if roverlay.hook.phase_allowed ( "user" ):
+         sys.exit (
+            roverlay.tools.shenv.run_script (
+               script         = extra_opts ['run_script'],
+               phase          = "user",
+               argv           = extra_opts ['run_script_args'],
+               return_success = False,
+               log_output     = False,
+               initial_dir    = os.getcwd(),
+            ).returncode
+         )
+      else:
+         die ( "--run-script: 'user' phase is not allowed." )
    elif do_setupdirs:
       sys.exit ( run_setupdirs (
          conf, extra_opts['target_uid'], extra_opts['target_gid']


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

commit:     55b83ffd569c0c3ce9ae46e6198805873864e8a4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 12 13:47:45 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 12 13:47:45 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=55b83ffd

roverlay, setupdirs command: dont load field def

---
 roverlay/__init__.py | 27 ++++++++++++++++-----------
 roverlay/main.py     |  2 ++
 2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index 175f2d1..f660a4a 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -30,17 +30,21 @@ def setup_initial_logger():
    """Sets up initial logging."""
    roverlay.recipe.easylogger.setup_initial()
 
-def load_config_file ( cfile, extraconf=None, setup_logger=True ):
+def load_config_file (
+   cfile, extraconf=None, setup_logger=True, load_main_only=False
+):
    """
    Loads the config, including the field definition file.
    Sets up the logger afterwards.
    (Don't call this method more than once.)
 
    arguments:
-   * cfile        -- path to the config file
-   * extraconf    -- a dict with additional config entries that will override
-                      entries read from cfile
-   * setup_logger -- set up logger (defaults to True)
+   * cfile          -- path to the config file
+   * extraconf      -- a dict with additional config entries that will override
+                        entries read from cfile
+   * setup_logger   -- set up logger (defaults to True)
+   * load_main_only -- if set and True: load main config file only
+                        (= do not load field def, ...)
    """
    roverlay_config = roverlay.config.access()
 
@@ -55,12 +59,13 @@ def load_config_file ( cfile, extraconf=None, setup_logger=True ):
    if setup_logger:
       roverlay.recipe.easylogger.setup ( roverlay_config )
 
-   confloader.load_field_definition (
-      roverlay_config.get_or_fail ( "DESCRIPTION.field_definition_file" )
-   )
+   if not load_main_only:
+      confloader.load_field_definition (
+         roverlay_config.get_or_fail ( "DESCRIPTION.field_definition_file" )
+      )
 
-   confloader.load_use_expand_map (
-      roverlay_config.get ( "EBUILD.USE_EXPAND.rename_file" )
-   )
+      confloader.load_use_expand_map (
+         roverlay_config.get ( "EBUILD.USE_EXPAND.rename_file" )
+      )
 
    return roverlay_config

diff --git a/roverlay/main.py b/roverlay/main.py
index 75d1e2f..0fec74d 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -101,6 +101,7 @@ def run_setupdirs ( config, target_uid, target_gid ):
                os.path.dirname ( value.rstrip ( os.sep ) )
                if dirmask & WANT_FILEDIR else value.rstrip ( os.sep )
             )
+
             if dirpath:
                dodir ( dirpath )
                if dirmask & WANT_PRIVATE:
@@ -459,6 +460,7 @@ def main (
          config_file,
          extraconf=additional_config,
          setup_logger=want_logging,
+         load_main_only=do_setupdirs,
       )
       del config_file, additional_config
    except:


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

commit:     5374a6066d9f8615243bba9b0a2d0c5be487f653
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Jun 22 15:03:05 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Jun 22 15:03:05 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5374a606

roverlay/packageinfo, revbump: set src_uri_dest

Rename distfiles of rev-bumped ebuilds.

---
 roverlay/packageinfo.py | 48 ++++++++++++++++++++++++++----------------------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 7b74425..b86d69d 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -94,6 +94,7 @@ class PackageInfo ( object ):
    PKGSUFFIX_REGEX = re.compile (
       config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$'
    )
+   EBUILDREV_REGEX = re.compile ( '[-]r[0-9]+$' )
    ALWAYS_FALLBACK = frozenset ( ( 'ebuild', 'ebuild_file' ) )
 
    _UPDATE_KEYS_SIMPLE         = frozenset ((
@@ -505,19 +506,36 @@ class PackageInfo ( object ):
 
    def revbump ( self, newrev=None ):
       """Do whatever necessary to revbump this pakages, that is set/update
-      all data like src_uri_destfile.
+      all data like src_uri_dest and ebuild_verstr.
 
       arguments:
       * newrev -- new revision, (current rev + 1) is used if this is None
       """
-      if newrev is None:
-         # get old rev and increment it
-         ## direct dict access
-         self._info ['rev'] += 1
-      else:
-         self._info ['rev'] = int ( newrev )
+      rev     = self._info['rev'] + 1 if newrev is None else int ( newrev )
+      rev_str = ( '-r' + str ( rev ) ) if rev > 0 else ''
+      vstr    = '.'.join ( str ( k ) for k in self ['version'] ) + rev_str
+
+      # preserve destpath directory
+      #  (this allows to handle paths like "a/b.tar/pkg.tgz" properly)
+      #
+      old_destpath = self ['package_src_destpath'].rpartition ( os.path.sep )
+
+      # os.path.splitext does not "recognize" .tar.gz
+      fhead, ftar, fext = old_destpath[2].rpartition ( '.tar' )
+      if not ftar:
+         fhead, fext = os.path.splitext ( fext )
+
+      # FIXME: any way to get this reliably (+faster) done without a regex?
+      #  ( a,b,c=fhead.rpartition ( '-r' ); try int(c) ...; ?)
+      distfile = (
+         old_destpath[0] + old_destpath[1]
+         + self.EBUILDREV_REGEX.sub ( '', fhead ) + rev_str + ftar + fext
+      )
+
+      self._info ['rev']           = rev
+      self._info ['ebuild_verstr'] = vstr
+      self._info ['src_uri_dest']  = distfile
 
-      self._reset_version_str()
       return self
    # --- end of revbump (...) ---
 
@@ -620,20 +638,6 @@ class PackageInfo ( object ):
          return None
    # --- end of get_evars (...) ---
 
-   def _reset_version_str ( self ):
-      """Recreates the version_str ($PVR) of this PackageInfo instance."""
-      rev     = self ['rev']
-      version = self ['version']
-
-      if rev > 0:
-         vstr = '.'.join ( str ( k ) for k in version ) + '-r' + str ( rev )
-      else:
-         vstr = '.'.join ( str ( k ) for k in version )
-
-      self._info ['ebuild_verstr'] = vstr
-      #return vstr
-   # --- end of _reset_version_str (...) ---
-
    def _update ( self, info ):
       """Updates self._info using the given info dict.
 


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

commit:     305933fc8ce3375745927cfda5fca824eb67f004
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Jun 22 10:31:24 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Jun 22 10:31:24 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=305933fc

roverlay/packageinfo: support revbumps

---
 roverlay/packageinfo.py | 91 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 35 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 83a05ed..b75eb8c 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -16,6 +16,8 @@ __all__ = [ 'PackageInfo', ]
 import re
 import os.path
 import logging
+# TODO: remove threading/locks here, exclusive access to PackageInfo instances
+#       should be guaranteed
 import threading
 
 import roverlay.digest
@@ -320,10 +322,6 @@ class PackageInfo ( object ):
          return self._info [key_low]
 
       # 'virtual' keys - calculate result
-      elif key_low == 'name':
-         # no special name, using package_name
-         return self._info ['package_name']
-
       elif key_low == 'package_file':
          distdir = self.get ( 'distdir', do_fallback=True )
          if distdir:
@@ -443,14 +441,14 @@ class PackageInfo ( object ):
       """Returns the DESCRIPTION data for this PackageInfo (by reading the
       R package file if necessary).
       """
-      if 'desc_data' in self._info:
-         return self._info ['desc_data']
-
-      self._writelock_acquire()
       if 'desc_data' not in self._info:
-         self._info ['desc_data'] = descriptionreader.read ( self )
+         self._writelock_acquire()
+         if 'desc_data' not in self._info:
+            self._info ['desc_data'] = descriptionreader.read ( self )
+
+         self._update_lock.release()
+      # -- end if;
 
-      self._update_lock.release()
       return self._info ['desc_data']
    # --- end of get_desc_data (...) ---
 
@@ -518,12 +516,14 @@ class PackageInfo ( object ):
       arguments:
       * newrev -- new revision, (current rev + 1) is used if this is None
       """
-      raise NotImplementedError ( "revbump code" )
       if newrev is None:
          # get old rev and increment it
-         pass
+         ## direct dict access
+         self._info ['rev'] += 1
       else:
-         pass
+         self._info ['rev'] = int ( newrev )
+
+      self._reset_version_str()
       return self
    # --- end of revbump (...) ---
 
@@ -635,6 +635,19 @@ class PackageInfo ( object ):
          return None
    # --- end of get_evars (...) ---
 
+   def _reset_version_str ( self ):
+      rev     = self ['rev']
+      version = self ['version']
+
+      if rev > 0:
+         vstr = '.'.join ( str ( k ) for k in version ) + '-r' + str ( rev )
+      else:
+         vstr = '.'.join ( str ( k ) for k in version )
+
+      self._info ['ebuild_verstr'] = vstr
+      #return vstr
+   # --- end of _reset_version_str (...) ---
+
    def _update ( self, info ):
       """Updates self._info using the given info dict.
 
@@ -645,15 +658,14 @@ class PackageInfo ( object ):
 
       for key, value in info.items():
 
-         if key in self.__class__._UPDATE_KEYS_SIMPLE:
-            self [key] = value
-
-         elif initial and key in self.__class__._UPDATE_KEYS_SIMPLE_INITIAL:
-            self [key] = value
+         if key in self.__class__._UPDATE_KEYS_SIMPLE or (
+            initial and key in self.__class__._UPDATE_KEYS_SIMPLE_INITIAL
+         ):
+            self._info [key] = value
 
          elif key in self.__class__._UPDATE_KEYS_FILTER_NONE:
             if value is not None:
-               self [key] = value
+               self._info [key] = value
 
          elif key == 'filename':
             self._use_filename ( value )
@@ -662,10 +674,10 @@ class PackageInfo ( object ):
             self._use_pvr ( value )
 
          elif key == 'suggests':
-            self ['has_suggests'] = value
+            self._info ['has_suggests'] = value
 
          elif key == 'depres_result':
-            self ['has_suggests'] = value [2]
+            self._info ['has_suggests'] = value [2]
 
          elif key == 'filepath':
             self._use_filepath ( value )
@@ -720,7 +732,7 @@ class PackageInfo ( object ):
 
       try:
          version = tuple ( int ( z ) for z in version_str.split ( '.' ) )
-         self ['version'] = version
+         self._info ['version'] = version
       except ValueError as ve:
          # version string is malformed, cannot use it
          self.logger.error (
@@ -736,24 +748,33 @@ class PackageInfo ( object ):
       # removing illegal chars from the package_name
       ebuild_name = strutil.fix_ebuild_name ( package_name )
 
-      if ebuild_name != package_name:
-         self ['name'] = ebuild_name
-
-      self ['ebuild_verstr']    = version_str
-
       # for DescriptionReader
-      self ['package_name']     = package_name
+      self._info ['package_name']     = package_name
 
-      self ['package_filename'] = filename_with_ext
+      self._info ['rev']              = 0
+      self._info ['name']             = ebuild_name
+      self._info ['ebuild_verstr']    = version_str
+      self._info ['package_filename'] = filename_with_ext
    # --- end of _use_filename (...) ---
 
    def _use_pvr ( self, pvr ):
-      # 0.1_pre2-r17 -> ( 0, 1 )
-      pv = pvr.partition ( '-' ) [0]
-      self ['version'] = tuple (
-         int ( z ) for z in ( pv.partition ( '_' ) [0].split ( '.' ) )
-      )
-      self ['ebuild_verstr'] = pvr
+      # 0.1_pre2-r17 -> ( ( 0, 1 ), ( 17 ) )
+      pv_str, DONT_CARE, pr_str    = pvr.partition    ( '-r' )
+      pv,     DONT_CARE, pv_suffix = pv_str.partition ( '_'  )
+
+      if pv_suffix:
+         # not supported
+         raise NotImplementedError (
+            "version suffix {!r} cannot be preserved for $PVR {!r}".format (
+               pv_suffix, pvr
+            )
+         )
+      # non-digit chars in pv are unsupported, too
+
+      self._info ['version'] = tuple ( int ( z ) for z in pv.split ( '.' ) )
+      self._info ['rev']     =  int ( pr_str ) if pr_str else 0
+
+      self._info ['ebuild_verstr'] = pvr
    # --- end of _use_pvr (...) ---
 
    def _remove_auto ( self, ebuild_status ):


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

commit:     7a98234f8f14a864be8a1ba2ebb8e45d202a9c00
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 20 23:38:38 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 20 23:38:38 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=7a98234f

roverlay/main: run hook after overlay creation

---
 roverlay/main.py | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/roverlay/main.py b/roverlay/main.py
index a0ca8e4..207bea6 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -81,6 +81,34 @@ def main (
          return call ( *args, **kw )
    # --- end of optionally (...) ---
 
+   def run_hook ( hook_key, phase ):
+      print ( "RUN_HOOK?", hook_key, phase )
+      script = roverlay.config.get ( hook_key, None )
+      if script:
+         print ( "YES.", str ( script ) )
+         return roverlay.tools.shenv.run_script (
+            script, phase.lower(), return_success=True
+         )
+      else:
+         print ( "NO." )
+         # nop
+         return True
+   # --- end of run_hook (...) ---
+
+   def run_hook_lazy ( phase ):
+      crelpath, sepa, ckey = phase.rpartition ( '_' )
+      if sepa:
+         # HOOK.~phase
+         cpath = (
+            'HOOK.' + crelpath.replace ( '_', '.' ).upper()
+            + '.' + ckey.lower()
+         )
+
+         return run_hook ( cpath, phase )
+      else:
+         raise Exception ( "cannot parse phase {!r}".format ( phase ) )
+   # --- end of run_hook_lazy (...) ---
+
    def run_sync():
       if "sync" in actions_done: return
       try:
@@ -284,6 +312,14 @@ def main (
          if OPTION ( 'print_stats' ):
             print ( "\n" + overlay_creator.stats_str() )
 
+
+         # FIXME/TODO:
+         #  this hook should be called _after_ verifying the overlay
+         #  (verification is not implemented yet)
+         #
+         if not run_hook_lazy ( 'overlay_success' ):
+            die ( "overlay_success hook returned non-zero", DIE.OV_CREATE )
+
          set_action_done ( "create" )
 
       except KeyboardInterrupt:
@@ -466,6 +502,9 @@ def main (
       try:
          from roverlay.remote          import RepoList
          from roverlay.overlay.creator import OverlayCreator
+
+         import roverlay.config
+         import roverlay.tools.shenv
       except ImportError:
          if HIDE_EXCEPTIONS:
             die ( "Cannot import roverlay modules!", DIE.IMPORT )


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

commit:     ddc3781f3fe2df940306c14a0ee2779a07454cb4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 20 23:27:41 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 20 23:27:41 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ddc3781f

roverlay/digest: fixup

---
 roverlay/digest.py | 86 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 54 insertions(+), 32 deletions(-)

diff --git a/roverlay/digest.py b/roverlay/digest.py
index 983ca1a..a031889 100644
--- a/roverlay/digest.py
+++ b/roverlay/digest.py
@@ -6,13 +6,19 @@
 
 """provides digest related utility functions (e.g. md5sum_file())"""
 
-__all__ = [ 'digest_compare', 'digest_supported',
-   'dodigest_file', 'md5sum_file'
+__all__ = [
+   'digest_compare', 'digest_comparator',
+   'digest_supported', 'dodigest_file',
+   'multihash', 'multihash_file',
+   'md5sum_file', 'sha1_file', 'sha256_file', 'sha512_file',
+   'whirlpool_file',
 ]
 
 import hashlib
 import portage.util.whirlpool
 
+DEFAULT_BLOCKSIZE=16384
+
 _HASH_CREATE_MAP = {
    'md5'       : hashlib.md5,
    'sha1'      : hashlib.sha1,
@@ -21,7 +27,10 @@ _HASH_CREATE_MAP = {
    'whirlpool' : portage.util.whirlpool.new,
 }
 
-def _generic_obj_hash ( hashobj, fh, binary_digest=False, blocksize=16384 ):
+
+def _generic_obj_hash (
+   hashobj, fh, binary_digest=False, blocksize=DEFAULT_BLOCKSIZE
+):
    block = fh.read ( blocksize )
    while block:
       hashobj.update ( block )
@@ -30,7 +39,17 @@ def _generic_obj_hash ( hashobj, fh, binary_digest=False, blocksize=16384 ):
    return hashobj.digest() if binary_digest else hashobj.hexdigest()
 # --- end of _hashsum_generic (...) ---
 
-def multihash ( fh, hashlist, binary_digest=False, blocksize=16384 ):
+def _generic_file_obj_hash (
+   hashobj, filepath, binary_digest=False, blocksize=DEFAULT_BLOCKSIZE
+):
+   with open ( filepath, 'rb' ) as fh:
+      ret = _generic_obj_hash ( hashobj, fh, binary_digest, blocksize )
+   return ret
+# --- end of _generic_file_obj_hash (...) ---
+
+def multihash (
+   fh, hashlist, binary_digest=False, blocksize=DEFAULT_BLOCKSIZE
+):
    """Calculates multiple digests for an already openened file and returns the
    resulting hashes as dict.
 
@@ -73,50 +92,53 @@ def multihash_file ( filepath, digest_types, **kwargs ):
       return dict()
 # --- end of multihash_file (...) ---
 
-def md5sum_file ( fh, binary_digest=False ):
-   """Returns the md5 sum for an already opened file."""
-   return _generic_obj_hash ( hashlib.md5(), fh, binary_digest )
+def md5sum_file ( filepath, **kw ):
+   """Returns the md5 sum for a file."""
+   return _generic_file_obj_hash ( hashlib.md5(), filepath, **kw )
 # --- end of md5sum_file (...) ---
 
-def sha1_file ( fh, binary_digest=False ):
-   return _generic_obj_hash ( hashlib.sha1(), fh, binary_digest )
+def sha1_file ( filepath, **kw ):
+   return _generic_obj_hash ( hashlib.sha1(), filepath, **kw )
 # --- end of sha1_file (...) ---
 
-def sha256_file ( fh, binary_digest=False ):
-   return _generic_obj_hash ( hashlib.sha256(), fh, binary_digest )
+def sha256_file ( filepath, **kw ):
+   return _generic_obj_hash ( hashlib.sha256(), filepath, **kw )
 # --- end of sha256_file (...) ---
 
-def sha512_file ( fh, binary_digest=False ):
-   return _generic_obj_hash ( hashlib.sha512(), fh, binary_digest )
+def sha512_file ( filepath, **kw ):
+   return _generic_obj_hash ( hashlib.sha512(), filepath, **kw )
 # --- end of sha512_file (...) ---
 
-def whirlpool_file ( fh, binary_digest=False ):
+def whirlpool_file ( filepath, **kw ):
    return _generic_obj_hash (
-      portage.util.whirlpool.new(), fh, binary_digest
+      portage.util.whirlpool.new(), filepath, **kw
    )
 # --- end of whirlpool_file (...) ---
 
-# TODO: remove
-_DIGEST_MAP = dict (
-   md5       = md5sum_file,
-   sha1      = sha1_file,
-   sha256    = sha256_file,
-   sha512    = sha512_file,
-   whirlpool = whirlpool_file,
-)
-
 def digest_supported ( digest_type ):
    """Returns True if the given digest type is supported, else False."""
-   return digest_type in _DIGEST_MAP
+   return digest_type in _HASH_CREATE_MAP
 # --- digest_supported (...) ---
 
-def dodigest_file ( _file, digest_type, binary_digest=False ):
-   ret = None
-   with open ( _file, mode='rb' ) as fh:
-      ret = _DIGEST_MAP [digest_type] ( fh, binary_digest=binary_digest )
-   return ret
+def dodigest_file ( _file, digest_type, **kwargs ):
+   return _generic_file_obj_hash (
+      hashobj       = _HASH_CREATE_MAP [digest_type](),
+      filepath      = _file,
+      **kwargs
+   )
 # --- end of dodigest_file (...) ---
 
-def digest_compare ( _file, digest, digest_type, binary_digest=False ):
-   return digest == dodigest_file ( _file, digest_type, binary_digest )
+def digest_compare ( digest, digest_type, filepath, **kwargs ):
+   return digest == dodigest_file ( filepath, digest_type, **kwargs )
 # --- end of digest_compare (...) ---
+
+# digest_comparator :: digest_type -> digest -> ( filepath, ... ) -> bool
+digest_comparator = (
+   lambda digest_type : (
+      lambda digest : (
+         lambda filepath, *args, **kwargs : digest_compare (
+            digest, digest_type, *args, **kwargs
+         )
+      )
+   )
+)


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-06-19 18:58 André Erdmann
  2013-06-22 15:24 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-06-19 18:58 UTC (permalink / raw
  To: gentoo-commits

commit:     daf73b9acc9191382332ef2e4582e906db9ad435
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun 19 18:51:35 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun 19 18:51:35 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=daf73b9a

packageinfo: create distmap data, make hashes

---
 roverlay/packageinfo.py | 43 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 90b4250..e8004d0 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -18,6 +18,8 @@ import os.path
 import logging
 import threading
 
+import roverlay.digest
+
 from roverlay          import config, strutil
 from roverlay.rpackage import descriptionreader
 
@@ -123,7 +125,7 @@ class PackageInfo ( object ):
       self._info               = dict()
       self.readonly            = False
       self._update_lock        = threading.RLock()
-      self.overlay_package_ref = None
+      #self.overlay_package_ref = None
       self.logger              = LOGGER
       #self._evars              = dict()
       #self._lazy_actions       = list()
@@ -373,9 +375,7 @@ class PackageInfo ( object ):
       elif key_low == 'package_src_destpath':
          # src file path relative to distroot (mirror root dir)
          destpath = self._info.get ('src_uri_dest', None )
-         return (
-            destpath or os.path.basename ( self._info ['package_filename'] )
-         )
+         return ( destpath or self._info ['package_filename'] )
 
       # end if <key matches ...>
 
@@ -450,6 +450,41 @@ class PackageInfo ( object ):
       return self._info ['desc_data']
    # --- end of get_desc_data (...) ---
 
+   def get_distmap_item ( self ):
+      return ( self.get_distmap_key(), self.get_distmap_value() )
+   # --- end of get_distmap_item (...) ---
+
+   def get_distmap_key ( self ):
+      return self.get ( "package_src_destpath" )
+   # --- end of get_distmap_key (...) ---
+
+   def get_distmap_value ( self ):
+      assert 'sha256' in self.hashdict
+
+      repo = self.get ( "origin" )
+      return (
+         repo.name,
+         os.path.relpath ( self.get ( "package_file" ), repo.distdir ),
+         self.hashdict ['sha256']
+      )
+   # --- end of get_distmap_value (...) ---
+
+   def make_hashes ( self, hashlist ):
+      pkgfile = self.get ( "package_file" )
+
+      if hasattr ( self, 'hashdict' ) and self.hashdict:
+         new_hashes = (
+            frozenset ( hashlist ) - frozenset ( self.hashdict.keys() )
+         )
+
+         if new_hashes:
+            self.hashdict.update (
+               roverlay.digest.multihash_file ( pkgfile, new_hashes )
+            )
+      else:
+         self.hashdict = roverlay.digest.multihash_file ( pkgfile, hashlist )
+   # --- end of make_hashes (...) ---
+
    def __getitem__ ( self, key ):
       """Returns an item."""
       return self.get ( key, do_fallback=False )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-06-19 18:58 André Erdmann
  2013-06-19 18:59 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-06-19 18:58 UTC (permalink / raw
  To: gentoo-commits

commit:     ce623a4736308104f0c11e27c2e94feeda7bbb26
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun 19 18:43:33 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun 19 18:43:33 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ce623a47

roverlay/digest: support sha* and multihash mode

This commit adds support for sha1/sha256/sha512 (via hashlib) and whirlpool (via
portage.util).

It also adds the mulihash[_file]() function(s) that create more than one digest
at once.

---
 roverlay/digest.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 82 insertions(+), 7 deletions(-)

diff --git a/roverlay/digest.py b/roverlay/digest.py
index 218f98c..983ca1a 100644
--- a/roverlay/digest.py
+++ b/roverlay/digest.py
@@ -11,23 +11,98 @@ __all__ = [ 'digest_compare', 'digest_supported',
 ]
 
 import hashlib
+import portage.util.whirlpool
 
-def md5sum_file ( fh, binary_digest=False ):
-   """Returns the md5 sum for an already opened file."""
-   md5 = hashlib.md5()
-   blocksize = 16384
+_HASH_CREATE_MAP = {
+   'md5'       : hashlib.md5,
+   'sha1'      : hashlib.sha1,
+   'sha256'    : hashlib.sha256,
+   'sha512'    : hashlib.sha512,
+   'whirlpool' : portage.util.whirlpool.new,
+}
 
+def _generic_obj_hash ( hashobj, fh, binary_digest=False, blocksize=16384 ):
    block = fh.read ( blocksize )
    while block:
-      md5.update ( block )
+      hashobj.update ( block )
       block = fh.read ( blocksize )
 
-   return md5.digest() if binary_digest else md5.hexdigest()
+   return hashobj.digest() if binary_digest else hashobj.hexdigest()
+# --- end of _hashsum_generic (...) ---
+
+def multihash ( fh, hashlist, binary_digest=False, blocksize=16384 ):
+   """Calculates multiple digests for an already openened file and returns the
+   resulting hashes as dict.
+
+   arguments:
+   * fh            -- file handle
+   * hashlist      -- iterable with hash names (e.g. md5)
+   * binary_digest -- whether the hashes should be binary or not
+   * blocksize     -- block size for reading
+   """
+   hashobj_dict = {
+      h: _HASH_CREATE_MAP[h]() for h in hashlist
+   }
+   block = fh.read ( blocksize )
+   while block:
+      for hashobj in hashobj_dict.values():
+         hashobj.update ( block )
+      block = fh.read ( blocksize )
+
+   if binary_digest:
+      return { h: hashobj.digest() for h, hashobj in hashobj_dict.items() }
+   else:
+      return { h: hashobj.hexdigest() for h, hashobj in hashobj_dict.items() }
+# --- end of multihash (...) ---
+
+def multihash_file ( filepath, digest_types, **kwargs ):
+   """Calculates multiple digests for the given file path.
+
+   Returns an empty dict if digest_types is empty.
+
+   arguments:
+   * filepath     --
+   * digest_types --
+   * **kwargs     -- passed to multihash()
+   """
+   if digest_types:
+      with open ( filepath, mode='rb' ) as fh:
+         hashdict = multihash ( fh, digest_types, **kwargs )
+      return hashdict
+   else:
+      return dict()
+# --- end of multihash_file (...) ---
+
+def md5sum_file ( fh, binary_digest=False ):
+   """Returns the md5 sum for an already opened file."""
+   return _generic_obj_hash ( hashlib.md5(), fh, binary_digest )
 # --- end of md5sum_file (...) ---
 
+def sha1_file ( fh, binary_digest=False ):
+   return _generic_obj_hash ( hashlib.sha1(), fh, binary_digest )
+# --- end of sha1_file (...) ---
+
+def sha256_file ( fh, binary_digest=False ):
+   return _generic_obj_hash ( hashlib.sha256(), fh, binary_digest )
+# --- end of sha256_file (...) ---
+
+def sha512_file ( fh, binary_digest=False ):
+   return _generic_obj_hash ( hashlib.sha512(), fh, binary_digest )
+# --- end of sha512_file (...) ---
+
+def whirlpool_file ( fh, binary_digest=False ):
+   return _generic_obj_hash (
+      portage.util.whirlpool.new(), fh, binary_digest
+   )
+# --- end of whirlpool_file (...) ---
 
+# TODO: remove
 _DIGEST_MAP = dict (
-   md5 = md5sum_file,
+   md5       = md5sum_file,
+   sha1      = sha1_file,
+   sha256    = sha256_file,
+   sha512    = sha512_file,
+   whirlpool = whirlpool_file,
 )
 
 def digest_supported ( digest_type ):


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

commit:     621d7b95dedf09850097304d1a3a4a9d87796591
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jun  4 20:32:14 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jun  4 20:32:14 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=621d7b95

packageinfo: doc, method stubs, set_direct_unsafe

* doc: PackageInfo key list

methods for new package rule actions (not committed yet):
* method stubs: attach_lazy_action()/apply_lazy_actions()
* set_direct_unsafe(): direct ("unsafe"!) write access to the info dict

---
 roverlay/packageinfo.py | 69 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 13 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index da3e5f1..c7c71eb 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -21,20 +21,34 @@ import threading
 from roverlay          import config, strutil
 from roverlay.rpackage import descriptionreader
 
+# PackageInfo info keys know to be used in roverlay's modules:
+# *** some keys are not listed here (FIXME) ***
 #
-# PackageInfo keys known to be used (read) in the roverlay modules:
+# * desc_data          -- dict containing DESCRIPTION data (created by
+#                          rpackage.descriptionreader.DescriptionReader)
+# * distdir            -- fs path to the directory containing the pkg (file)
+# * ebuild             -- object representing the ebuild (printable via str())
+# * ebuild_file        -- fs path to the ebuild file (str)
+# * ebuild_verstr      -- version string as it's used in the ebuild
+# * has_suggests       -- bool that indicates whether a package has optional
+#                          dependencies
+# * name               -- (ebuild) name of a package (no "special" chars etc.)
+# * orig_name          -- original (ebuild) name (before "name" has been
+#                          modified by package rules)
+# * origin             -- a package's origin (repository object)
+# * package_file       -- full fs path to the package file
+# * package_filename   -- file name (including file extension)
+# * package_name       -- package name (file name without version, f-ext)
+# * physical_only      -- bool that indicates whether a package exists as
+#                          ebuild file only (True) or has additional
+#                          runtime data (False)
+# * src_uri            -- SRC_URI for a package
+# * version            -- tuple containing a package's version
 #
-# * desc_data        in ebuild/creation, metadata/__init__
-# * distdir          in manifest/helpers
-# * ebuild           in overlay/package
-# * ebuild_file      in manifest/helpers, overlay/package
-# * ebuild_verstr    in overlay/package
-# * name             in ebuild/creation, overlay/category
-# * package_file     in rpackage/descriptionreader
-# * package_name     in rpackage/descriptionreader
-# * package_url      in ebuild/creation
-# * physical_only    in overlay/pacakge
-# * version          in ebuild/package (as tuple)
+
+#
+# FIXME/TOOD: don't overwrite name (package rules are applied _before_ reading
+#             desc data)
 #
 
 LOGGER = logging.getLogger ( 'PackageInfo' )
@@ -97,15 +111,33 @@ class PackageInfo ( object ):
       * **initial_info -- passed to update ( **kw )
       """
       self._info               = dict()
-      #self._evars              = dict()
       self.readonly            = False
       self._update_lock        = threading.RLock()
       self.overlay_package_ref = None
       self.logger              = LOGGER
+      #self._evars              = dict()
+      #self.lazy_actions        = list()
+      #(or set(), but list preserves order for actions with the same condition)
 
       self.update ( **initial_info )
    # --- end of __init__ (...) ---
 
+   def attach_lazy_action ( self, lazy_action ):
+      """Attaches a lazy action.
+      Unsafe operation (no locks will be acquired etc.).
+
+      arguments:
+      * lazy_action --
+      """
+      raise NotImplementedError ( "method stub" )
+   # --- end of attach_lazy_action (...) ---
+
+   def apply_lazy_actions ( self ):
+      """Tries to apply all attached (lazy) actions.
+      Removes actions that have been applied."""
+      raise NotImplementedError ( "method stub" )
+   # --- end of apply_lazy_actions (...) ---
+
    def set_readonly ( self, immediate=False, final=False ):
       """Makes the package info readonly.
 
@@ -357,6 +389,17 @@ class PackageInfo ( object ):
       self._update_lock.release()
    # --- end of __setitem__ (...) ---
 
+   def set_direct_unsafe ( self, key, value ):
+      """Sets an item. This operation is unsafe (no locks will be acquired,
+      write-accessibility won't be checked, data won't be validated).
+
+      arguments:
+      * key   --
+      * value --
+      """
+      self._info [key] = value
+   # --- end of set_direct_unsafe (...) ---
+
    def update_now ( self, **info ):
       """Updates the package info data with temporarily enabling write access.
       Data will be readonly after calling this method.


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-06-05 18:08 André Erdmann
  2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-06-05 18:08 UTC (permalink / raw
  To: gentoo-commits

commit:     7e66abd0a28b088f3a657f483b1ed091b5d9a938
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun  5 18:04:02 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun  5 18:04:02 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=7e66abd0

roverlay/main: --fixup-category-move[-reverse]

---
 roverlay/argutil.py | 30 ++++++++++++++++++++++++++++--
 roverlay/main.py    |  5 +++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 689fe78..90d95df 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -88,7 +88,9 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
       ),
       add_help=True,
       formatter_class=argparse.RawDescriptionHelpFormatter,
-      )
+   )
+
+   incremental_mutex = parser.add_mutually_exclusive_group()
 
    arg     = parser.add_argument
    opt_in  = dict ( default=False, action='store_true' )
@@ -223,6 +225,28 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
       action='store_true',
    )
 
+   incremental_mutex.add_argument (
+      '--fixup-category-move',
+      help='''
+         remove packages from the default category
+         if they exist in another one
+      ''',
+      dest='fixup_category_move',
+      default=None,
+      action='store_true'
+   )
+
+   incremental_mutex.add_argument (
+      '--fixup-category-move-reverse',
+      help='''
+         remove packages from other categories if they exist in the
+         default one
+      ''',
+      default=None,
+      dest='fixup_category_move_rev',
+      action='store_true'
+   )
+
    arg (
       '--stats',
       help="print some stats",
@@ -288,7 +312,7 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
    # --no-incremental currently means that an existing overlay won't be
    # scanned for ebuilds (which means that ebuilds will be recreated),
    # but old ebuilds won't be explicitly removed
-   arg (
+   incremental_mutex.add_argument (
       '--no-incremental',
       help="start overlay creation from scratch (ignore an existing overlay)",
       dest='incremental',
@@ -365,6 +389,8 @@ def parse_argv ( command_map, **kw ):
       incremental             = p.incremental,
       immediate_ebuild_writes = p.immediate_ebuild_writes,
       dump_file               = p.dump_file,
+      fixup_category_move     = p.fixup_category_move,
+      fixup_category_move_rev = p.fixup_category_move_rev,
    )
 
    if given ( 'overlay' ):

diff --git a/roverlay/main.py b/roverlay/main.py
index ab75099..a0ca8e4 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -272,6 +272,11 @@ def main (
 
          overlay_creator.release_package_rules()
 
+         if OPTION ( 'fixup_category_move' ):
+            overlay_creator.remove_moved_ebuilds ( reverse=False )
+         elif OPTION ( 'fixup_category_move_rev' ):
+            overlay_creator.remove_moved_ebuilds ( reverse=True )
+
          overlay_creator.run ( close_when_done=True )
 
          optionally ( overlay_creator.write_overlay, 'write_overlay' )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/
@ 2013-06-05 18:08 André Erdmann
  2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2013-06-05 18:08 UTC (permalink / raw
  To: gentoo-commits

commit:     6614a65b9d90716e1648529900cc2241981d5dab
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun  5 17:58:41 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun  5 17:58:41 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6614a65b

packageinfo: add support for lazy actions

This feature is disabled because it's not used and would therefore only add
overhead.

---
 roverlay/packageinfo.py | 41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index c7c71eb..5962867 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -45,10 +45,19 @@ from roverlay.rpackage import descriptionreader
 # * src_uri            -- SRC_URI for a package
 # * version            -- tuple containing a package's version
 #
-
 #
-# FIXME/TOOD: don't overwrite name (package rules are applied _before_ reading
-#             desc data)
+# Info (keys) that are created before applying package rules:
+#
+# * distdir
+# * origin
+# * package_{file{,name},name}
+# * name (package_name)
+# * src_uri (src_uri_base)
+#
+# "Foreign" info keys (never set or modified here):
+#
+# * category
+# * src_uri_dest
 #
 
 LOGGER = logging.getLogger ( 'PackageInfo' )
@@ -116,7 +125,7 @@ class PackageInfo ( object ):
       self.overlay_package_ref = None
       self.logger              = LOGGER
       #self._evars              = dict()
-      #self.lazy_actions        = list()
+      #self._lazy_actions       = list()
       #(or set(), but list preserves order for actions with the same condition)
 
       self.update ( **initial_info )
@@ -129,13 +138,28 @@ class PackageInfo ( object ):
       arguments:
       * lazy_action --
       """
-      raise NotImplementedError ( "method stub" )
+      raise NotImplementedError ( "lazy actions are disabled." )
+      if hasattr ( self, '_lazy_actions' ):
+         self._lazy_actions.append ( lazy_action )
+      else:
+         self._lazy_actions = [ lazy_action ]
    # --- end of attach_lazy_action (...) ---
 
    def apply_lazy_actions ( self ):
       """Tries to apply all attached (lazy) actions.
       Removes actions that have been applied."""
-      raise NotImplementedError ( "method stub" )
+      raise NotImplementedError ( "lazy actions are disabled." )
+      if hasattr ( self, '_lazy_actions' ):
+         retry_later = list()
+         for action in self._lazy_actions:
+            if not action.try_apply_action ( self ):
+               retry_later.append ( action )
+
+         if retry_later:
+            self._lazy_actions = retry_later
+         else:
+            del self._lazy_actions
+      # -- end if;
    # --- end of apply_lazy_actions (...) ---
 
    def set_readonly ( self, immediate=False, final=False ):
@@ -529,6 +553,11 @@ class PackageInfo ( object ):
                "in _update(): unknown info key {}!".format ( key )
             )
       # -- end for;
+
+      # FIXME (if needed):
+      #  the package rule parser doesn't create lazy actions, currently,
+      #  so calling apply_lazy_actions() would do nothing
+      ##self.apply_lazy_actions()
    # --- end of _update (...) ---
 
    def _use_filename ( self, _filename ):


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

commit:     a3647944a790117bd668c48f578b3d3fcfe2d5d3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon May 13 18:48:28 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon May 13 18:48:28 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a3647944

'apply_rules' command: count modified packages

---
 roverlay/main.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 6 deletions(-)

diff --git a/roverlay/main.py b/roverlay/main.py
index 7090689..c3f919b 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -130,6 +130,8 @@ def main (
 		# track package rules
 		prules.add_trace_actions()
 
+		NUM_MODIFIED = 0
+
 
 		BEGIN_RECEIVE_PACKAGE = ( 8 * '-' ) + " {header} " + ( 8 * '-' ) + '\n'
 		END_RECEIVE_PACKAGE   = ( 31 * '-' ) + '\n\n'
@@ -138,6 +140,28 @@ def main (
 			header = ( p ['name'] + ' ' + p ['ebuild_verstr'] )
 		)
 
+		def bool_counter ( f ):
+			"""Wrapper that returns a 2-tuple (result_list, function f').
+			f' which increases result_list first or second element depending
+			on the return value of function f.
+
+			arguments:
+			* f -- function to wrap
+			"""
+			result_list = [ 0, 0 ]
+
+			def wrapped ( *args, **kwargs ):
+				result = f ( *args, **kwargs )
+				if result:
+					result_list [0] += 1
+				else:
+					result_list [1] += 1
+				return result
+			# --- end of wrapped (...) ---
+
+			return result_list, wrapped
+		# --- end of bool_counter (...) ---
+
 		def receive_package ( P ):
 			if prules.apply_actions ( P ):
 				if hasattr ( P, 'modified_by_package_rules' ):
@@ -152,20 +176,58 @@ def main (
 						for evar in evars:
 							FH.write ( "* {}\n".format ( evar ) )
 
+
+					if  P.modified_by_package_rules is not True:
+						# ^ check needs to be changed when adding more trace actions
+						FH.write ( "trace marks:\n" )
+						for s in P.modified_by_package_rules:
+							if s is not True:
+								FH.write ( "* {}\n".format ( s ) )
+
 					FH.write ( END_RECEIVE_PACKAGE )
+				else:
+					# not modified
+					return False
 			else:
 				FH.write ( get_header ( P ) )
 				FH.write ( "filtered out!\n" )
 				FH.write ( END_RECEIVE_PACKAGE )
 
+			# modifed
+			return True
 		# --- end of receive_package (...) ---
 
-		if dump_file == "-":
-			FH = sys.stdout
-			repo_list.add_packages ( receive_package )
-		else:
-			with open ( dump_file, 'wt' ) as FH:
-				repo_list.add_packages ( receive_package )
+		modify_counter, receive_package_counting = bool_counter ( receive_package )
+
+		try:
+			if dump_file == "-":
+				FH_SHARED = True
+				FH = sys.stdout
+			else:
+				FH_SHARED = False
+				FH = open ( dump_file, 'wt' )
+
+			time_start = time.time()
+			repo_list.add_packages ( receive_package_counting )
+			time_add_packages = time.time() - time_start
+
+			if modify_counter [0] > 0:
+				FH.write ( "\n" )
+
+			#FH.write (
+			sys.stdout.write (
+				'done after {t} seconds\n'
+				'{p} packages processed in total, out of which '
+				'{m} have been modified or filtered out\n'.format (
+					t = round ( time_add_packages, 1 ),
+					p = ( modify_counter [0] + modify_counter [1] ),
+					m = modify_counter [0]
+				)
+			)
+
+		finally:
+			if 'FH' in locals() and not FH_SHARED:
+				FH.close()
 
 	# --- end of run_apply_package_rules (...) ---
 


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

commit:     311ac182bba51393153f1c4de4b2580461023608
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Apr 23 00:56:13 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Apr 23 00:56:13 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=311ac182

roverlay/main: apply_rules command

This command applies the package rules to all packages and prints the result
(package filtered out, package modifed: evar...) to stdout (or to --dump-file).

---
 roverlay/argutil.py |   26 ++++++++++++++
 roverlay/main.py    |   92 +++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 100 insertions(+), 18 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 23804b6..7237eba 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -29,6 +29,19 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 			)
 		return f
 
+	def couldbe_fs_file ( value ):
+		if value:
+			f = os.path.abspath ( value )
+			if not os.path.exists ( f ) or os.path.isfile ( f ):
+				return f
+
+		raise argparse.ArgumentTypeError (
+			"{!r} is not a file.".format ( value )
+		)
+
+	def couldbe_stdout_or_file ( value ):
+		return value if value == "-" else couldbe_fs_file ( value )
+
 	def is_fs_dir ( value ):
 		d = os.path.abspath ( value )
 		if not os.path.isdir ( d ):
@@ -283,6 +296,18 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 		action='store_false',
 	)
 
+	arg (
+		'--dump-file',
+		help='''
+			standard file or stdout target for dumping information
+			(defaults to '-'). Used by the 'apply_rules' action.
+		''',
+		dest="dump_file",
+		default="-",
+		metavar="<file>",
+		type=couldbe_stdout_or_file,
+	)
+
 #	# TODO
 #	arg (
 #		'--debug',
@@ -339,6 +364,7 @@ def parse_argv ( command_map, **kw ):
 		skip_manifest           = p.no_manifest,
 		incremental             = p.incremental,
 		immediate_ebuild_writes = p.immediate_ebuild_writes,
+		dump_file               = p.dump_file,
 	)
 
 	if given ( 'overlay' ):

diff --git a/roverlay/main.py b/roverlay/main.py
index b525ffe..7090689 100644
--- a/roverlay/main.py
+++ b/roverlay/main.py
@@ -119,6 +119,56 @@ def main (
 				raise
 	# --- end of run_sync() ---
 
+	def run_apply_package_rules():
+		if "apply_rules" in actions_done: return
+
+		dump_file = OPTION ( "dump_file" )
+		FH        = None
+
+		prules = PackageRules.get_configured()
+
+		# track package rules
+		prules.add_trace_actions()
+
+
+		BEGIN_RECEIVE_PACKAGE = ( 8 * '-' ) + " {header} " + ( 8 * '-' ) + '\n'
+		END_RECEIVE_PACKAGE   = ( 31 * '-' ) + '\n\n'
+
+		get_header = lambda p : BEGIN_RECEIVE_PACKAGE.format (
+			header = ( p ['name'] + ' ' + p ['ebuild_verstr'] )
+		)
+
+		def receive_package ( P ):
+			if prules.apply_actions ( P ):
+				if hasattr ( P, 'modified_by_package_rules' ):
+					# ^ that check is sufficient here
+					#if P.modified_by_package_rules
+
+					FH.write ( get_header ( P ) )
+
+					evars = P.get_evars()
+					if evars:
+						FH.write ( "evars applied:\n" )
+						for evar in evars:
+							FH.write ( "* {}\n".format ( evar ) )
+
+					FH.write ( END_RECEIVE_PACKAGE )
+			else:
+				FH.write ( get_header ( P ) )
+				FH.write ( "filtered out!\n" )
+				FH.write ( END_RECEIVE_PACKAGE )
+
+		# --- end of receive_package (...) ---
+
+		if dump_file == "-":
+			FH = sys.stdout
+			repo_list.add_packages ( receive_package )
+		else:
+			with open ( dump_file, 'wt' ) as FH:
+				repo_list.add_packages ( receive_package )
+
+	# --- end of run_apply_package_rules (...) ---
+
 	def run_overlay_create():
 		if "create" in actions_done: return
 		#run_sync()
@@ -182,6 +232,7 @@ def main (
 			'run an interactive depres console (highly experimental)',
 		'depres'         : 'this is an alias to \'depres_console\'',
 		'nop'            : 'does nothing',
+		'apply_rules'    : 'apply package rules verbosely and exit afterwards',
 	}
 
 
@@ -217,6 +268,8 @@ def main (
 	# imports roverlay.remote, roverlay.overlay.creator
 
 	actions = set ( filter ( lambda x : x != 'nop', commands ) )
+	actions_done = set()
+	set_action_done = actions_done.add
 
 	if 'sync' in actions and OPTION ( 'nosync' ):
 		die ( "sync command blocked by --nosync opt.", DIE.ARG )
@@ -282,11 +335,13 @@ def main (
 
 		import roverlay.packagerules.rules
 
+		package_rules = (
+			roverlay.packagerules.rules.PackageRules.get_configured()
+		)
+
 		HLINE = "".rjust ( 79, '-' )
 		print ( HLINE )
-		print (
-			str ( roverlay.packagerules.rules.PackageRules.get_configured() )
-		)
+		print ( str ( package_rules ) )
 		print ( HLINE )
 
 		EXIT_AFTER_CONFIG = True
@@ -294,8 +349,7 @@ def main (
 	# -- end of EXIT_AFTER_CONFIG entries
 
 	if 'EXIT_AFTER_CONFIG' in locals() and EXIT_AFTER_CONFIG:
-		pass
-		#sys.exit ( os.EX_OK )
+		sys.exit ( os.EX_OK )
 
 	# switch to depres console
 	elif 'depres_console' in actions or 'depres' in actions:
@@ -306,7 +360,7 @@ def main (
 			from roverlay.depres.simpledeprule.console import DepResConsole
 			con = DepResConsole()
 			con.run()
-			sys.exit ( os.EX_OK )
+			set_action_done ( "depres_console" )
 		except ImportError:
 			if HIDE_EXCEPTIONS:
 				die ( "Cannot import depres console!", DIE.IMPORT )
@@ -332,25 +386,27 @@ def main (
 				raise
 
 		# -- run methods (and some vars)
-		# imports: nothing
+		# imports: package rules
 
 		#repo_list       = None
 		#overlay_creator = None
 
-		actions_done = set()
-		set_action_done = actions_done.add
-
 		# -- run
 
-		# always run sync 'cause commands = {create,sync}
-		# and create implies (no)sync
+		# always run sync 'cause commands = {create,sync,apply_rules}
+		# and create,apply_rules implies (no)sync
 		run_sync()
 
-		if 'create' in actions: run_overlay_create()
+		if "apply_rules" in actions:
+			from roverlay.packagerules.rules import PackageRules
+			run_apply_package_rules()
+		elif 'create' in actions:
+			run_overlay_create()
 
-		if len ( actions ) > len ( actions_done ):
-			die (
-				"Some actions (out of {!r}) could not be performed!".format (
-					actions ), DIE.CMD_LEFTOVER
-			)
+
+	if len ( actions ) > len ( actions_done ):
+		die (
+			"Some actions (out of {!r}) could not be performed!".format (
+				actions ), DIE.CMD_LEFTOVER
+		)
 # --- end of main (...) ---


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

commit:     4f5260ef21e696548fbf04a54bc67df21ff86aa7
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sun Mar 17 11:54:34 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sun Mar 17 16:06:22 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4f5260ef

strutil: add additional_filter to ascii_filter()

The additional_filter arg should be None or a function Char -> Bool
that can be used to filter out unwanted ascii chars without the need
of an extra string iteration.

---
 roverlay/strutil.py |   19 ++++++++++++++++---
 1 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index f5ab8fd..f0d60df 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -52,9 +52,22 @@ def fix_ebuild_name ( name ):
 	)
 # --- end of fix_ebuild_name (...) ---
 
-def ascii_filter ( _str ):
-	"""Removes all non-ascii chars from a string and returns the result."""
-	return ''.join ( c for c in _str if ord ( c ) < 128 )
+def ascii_filter ( _str, additional_filter=None ):
+	"""Removes all non-ascii chars from a string and returns the result.
+
+	arguments:
+	* _str              -- string to be filtered
+	* additional_filter -- a function that is called for each ascii char
+	                       and returns true if the char is allowed (i.e.,
+	                       should be kept in the resulting string), else False.
+	                       Defaults to None, which means "keep all".
+	"""
+	if additional_filter is None:
+		return ''.join ( c for c in _str if ord ( c ) < 128 )
+	else:
+		return ''.join (
+			c for c in _str if ord ( c ) < 128 and additional_filter ( c )
+		)
 # --- end of ascii_filter (...) ---
 
 def shorten_str ( s, maxlen, replace_end=None ):


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

commit:     f7b72377d6de31460a846ef265949bb87327b7f0
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Mar  5 11:19:02 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Mar  5 11:19:02 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f7b72377

argutil: rename --distdir to --local-distdir

The meaning of "distdir" has changed as it is also used for
Manifest file creation and as package mirror directory while
'--distdir' means "create ebuilds for packages from a local directory".

---
 roverlay/argutil.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index d7d8444..23804b6 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -135,7 +135,7 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 	)
 
 	arg (
-		'--distdir', '--from', default=argparse.SUPPRESS,
+		'--local-distdir', '--from', default=argparse.SUPPRESS,
 		action='append',
 		help='''
 			use packages from %(metavar)s for ebuild creation (ignore all repos).


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

commit:     dd748310b8ed1b939b9da9d1efad0babfdacd2e0
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat Feb  9 19:11:55 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat Feb  9 20:08:14 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=dd748310

packageinfo: _remove_auto(), fix has_key*()

_remove_auto() deletes keys that are no longer required now instead of
creating a new dict() (behavior changed from a "whitelist"- to a "blacklist"
approach)

has_key()/has_key_or(): catch KeyError and log it as error since
<package>.get( key, do_fallback=True ) should not raise it.

---
 roverlay/packageinfo.py |   65 ++++++++++++++++++++++++----------------------
 1 files changed, 34 insertions(+), 31 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 438433c..05c6feb 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -60,10 +60,9 @@ class PackageInfo ( object ):
 	                                 no keys have been stored)
 	* _UPDATE_KEYS_FILTER_NONE    -- like _UPDATE_KEYS_SIMPLE, but stores
 	                                 key's value only if it is not None
-	* _REMOVE_KEYS_KEEP_EBUILD    -- a set of keys that will be kept when
+	* _REMOVE_KEYS_EBUILD         -- a set of keys that will be removed when
 	                                 _remove_auto ( 'ebuild_written' ) is
 	                                 called.
-	                                 These keys must exist at this point!
 	"""
 
 	EBUILDVER_REGEX = re.compile ( '[-]{1,}' )
@@ -87,9 +86,8 @@ class PackageInfo ( object ):
 		'distdir',
 	))
 
-	_REMOVE_KEYS_KEEP_EBUILD    = frozenset ((
-		'distdir', 'desc_data', 'ebuild_file', 'version',
-		'ebuild_filename', 'package_name', 'package_filename',
+	_REMOVE_KEYS_EBUILD         = frozenset ((
+		'ebuild'
 	))
 
 	def __init__ ( self, **initial_info ):
@@ -169,6 +167,14 @@ class PackageInfo ( object ):
 		return True
 	# --- end of _writelock_acquire (...) ---
 
+	def _has_log_keyerror_unexpected ( self, key, error ):
+		self.logger.error (
+			'FIXME: PackageInfo.get( {!r}, do_fallback=True ) '
+			'raised KeyError'.format ( key )
+		)
+		self.logger.exception ( error )
+	# --- end of _has_log_keyerror_unexpected (...) ---
+
 	def has_key ( self, *keys ):
 		"""Returns False if at least one key out of keys is not accessible,
 		i.e. its data cannot be retrieved using get()/__getitem__().
@@ -180,7 +186,11 @@ class PackageInfo ( object ):
 			if k not in self._info:
 				# try harder - use get() with fallback value to see if value
 				# can be calculated
-				if self.get ( k, do_fallback=True ) is None:
+				try:
+					if self.get ( k, do_fallback=True ) is None:
+						return False
+				except KeyError as kerr:
+					self._has_log_keyerror_unexpected ( k, kerr )
 					return False
 		return True
 	# --- end of has_key (...) ---
@@ -194,10 +204,13 @@ class PackageInfo ( object ):
 		* *keys -- keys to check
 		"""
 		for k in keys:
-			if k in self._info:
-				return True
-			elif self.get ( k, do_fallback=True ) is not None:
-				return True
+			try:
+				if k in self._info:
+					return True
+				elif self.get ( k, do_fallback=True ) is not None:
+					return True
+			except KeyError as kerr:
+				self._has_log_keyerror_unexpected ( k, kerr )
 		return False
 	# --- end of has_key_or (...) ---
 
@@ -248,11 +261,11 @@ class PackageInfo ( object ):
 			return self._info ['package_name']
 
 		elif key_low == 'package_file':
-			# assuming that origin is in self._info
-			return os.path.join (
-				self.get ( 'distdir' ),
-				self._info ['package_filename']
-			)
+			distdir = self.get ( 'distdir', do_fallback=True )
+			if distdir:
+				fname = self._info.get ( 'package_filename', None )
+				if fname:
+					return distdir + os.path.sep + fname
 
 		elif key_low == 'distdir':
 			if 'origin' in self._info:
@@ -524,24 +537,14 @@ class PackageInfo ( object ):
 		with self._update_lock:
 
 			if ebuild_status == 'ebuild_written':
-				# selectively copying required keys to a new info dict
-
-				to_keep = self.__class__._REMOVE_KEYS_KEEP_EBUILD
-
-				# needs python >= 2.7
-				info_new = { k : self.get ( k ) for k in to_keep }
 
-				# also add an ebuild stub to the new dict to indicate
-				# that this PackageInfo instance has been created from been
-				# created from an R package in this script run
-				info_new ['ebuild'] = True
+				# selectively deleting entries that are no longer required
 
-				if 'physical_only' in self._info:
-					info_new ['physical_only'] = self._info ['physical_only']
-
-				info_old   = self._info
-				self._info = info_new
-				del info_old
+				for key in self.__class__._REMOVE_KEYS_EBUILD:
+					try:
+						del self._info [key]
+					except KeyError:
+						pass
 			# -- if
 		# -- lock
 	# --- end of _remove_auto (...) ---


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

commit:     1b78546536ddad0c80eaa6c98d4e073f0c7c3357
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Feb  5 17:26:31 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Feb  5 17:26:31 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1b785465

roverlay/util: for_all_files(), get_dict_hash()

for_all_files(): accepts a list of "files or dirs" and calls a function
                 for each file (dirs will be recursively expanded)

get_dict_hash(): a (slow) function that creates a hash for a dict
                 by hashing a frozenset of (key,value)-tuples

---
 roverlay/util.py |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 55 insertions(+), 1 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index 8f737c1..4712b63 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -6,13 +6,56 @@
 
 """provides utility functions commonly used"""
 
-__all__= [ 'dodir', 'keepenv', 'sysnop', 'get_dict_hash', 'priosort', ]
+__all__= [
+	'dodir', 'keepenv', 'sysnop', 'get_dict_hash', 'priosort',
+	'for_all_files'
+]
 
 import os
 import logging
 
 LOGGER = logging.getLogger ( 'util' )
 
+def for_all_files (
+	files_or_dirs, func,
+	args=(), kwargs={}, file_filter=None, ignore_missing=False
+):
+	"""
+	Runs "func ( <file>, *args, **kwargs )" for each <file> in files_or_dirs.
+	Dirs will be recursively "expanded" (= for all files/dirs in dir...).
+
+	arguments:
+	* files_or_dirs  -- an iterable with files or dirs
+	* func           -- function that will be called for each file
+	* args           -- args that will be passed to each func call
+	                     Defaults to () (empty tuple)
+	* kwargs         -- keyword args that will be passed to each func call
+	                     Defaults to {} (empty dict)
+	* file_filter    -- if not None: func will only be called if this function
+	                                 returns True for <file>
+	                     Defaults to None
+	* ignore_missing -- if True: do not raise an exception if a file/dir is
+	                             missing
+	                     Defaults to False
+	"""
+	# alternative: os.walk()
+	def recursive_do ( fpath ):
+		if os.path.isfile ( fpath ):
+			if file_filter is None or file_filter ( fpath ):
+				func ( fpath, *args, **kwargs )
+		elif os.path.isdir ( fpath ):
+			for fname in os.listdir ( fpath ):
+				recursive_do ( fpath + os.sep + fname )
+		elif os.access ( fpath, os.F_OK ):
+			raise Exception ( "{}: neither a file nor a dir.".format ( fpath ) )
+		elif not ignore_missing:
+			raise Exception ( "{!r} does not exist!".format ( fpath ) )
+	# --- end of recursive_do (...) ---
+
+	for f in files_or_dirs:
+		recursive_do ( f )
+# --- end of for_all_files (...) ---
+
 def priosort ( iterable ):
 	"""Sorts the items of an iterable by priority (lower value means higher
 	priority).
@@ -32,6 +75,17 @@ def priosort ( iterable ):
 	return sorted ( iterable, key=priokey )
 # --- end of priosort (...) ---
 
+def get_dict_hash ( kwargs ):
+	# dict is not hashable, instead hash a frozenset of (key,value) tuples
+	# !!! this operations costs (time)
+	return hash (
+		frozenset (
+			( k, v ) for k, v in kwargs.items()
+		)
+	)
+# --- end of get_dict_hash (...) ---
+
+
 def keepenv ( *to_keep ):
 	"""Selectively imports os.environ.
 


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

commit:     24e73a658d50c29d4acc60f91722706a73719386
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Feb  5 17:25:53 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Feb  5 17:25:53 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=24e73a65

roverlay/strutil: wildcard_to_regex()

---
 roverlay/strutil.py |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 4a5ef5d..f5ab8fd 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -23,6 +23,20 @@ def split_whitespace ( _str, **kwargs ):
 	return _WHITESPACE.split ( _str, **kwargs )
 # --- end of split_whitespace (...) ---
 
+def wildcard_to_regex ( _str, unsafe ):
+	# TODO: find a function that is more efficient
+	if unsafe:
+		return _str.replace ( '?', '.' ).replace ( '*', '.*?' )
+	else:
+		return '[*]'.join (
+			(
+				'[?]'.join (
+					i.replace ( '?', '.' ) for i in a.split ( '\\?' )
+				).replace ( '*', '.*?' )
+			) for a in _str.split ( '\\*' )
+		)
+# --- end of wildcard_to_regex (...) ---
+
 def fix_ebuild_name ( name ):
 	"""Removes illegal chars from an ebuild name by replacing them with an
 	underscore char '_'.


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

commit:     9a715ef8a5c0553b85184b423f977cced4648adb
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jan 30 20:05:51 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jan 30 20:05:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9a715ef8

util: priosort()

Sorts the items of an iterable by priority.

---
 roverlay/util.py |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index be2cd33..8f737c1 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -6,13 +6,32 @@
 
 """provides utility functions commonly used"""
 
-__all__= [ 'dodir', 'keepenv', 'sysnop', ]
+__all__= [ 'dodir', 'keepenv', 'sysnop', 'get_dict_hash', 'priosort', ]
 
 import os
 import logging
 
 LOGGER = logging.getLogger ( 'util' )
 
+def priosort ( iterable ):
+	"""Sorts the items of an iterable by priority (lower value means higher
+	priority).
+
+	arguments:
+	* iterable
+	"""
+	def priokey ( item ):
+		"""Returns the priority of an item.
+
+		arguments:
+		* item --
+		"""
+		return item.priority
+	# --- end of priokey (...) ---
+
+	return sorted ( iterable, key=priokey )
+# --- end of priosort (...) ---
+
 def keepenv ( *to_keep ):
 	"""Selectively imports os.environ.
 


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

commit:     78675495ed708852d5771ebd98aec38d0c2ed6ab
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jan 30 19:57:42 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jan 30 20:00:33 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=78675495

packageinfo: update_unsafe(), add ebuild variables

new function update_unsafe() that simply adds information to a PackageInfo
instance without locking or checking for writability.

added EVAR* key that can be used to add per-package ebuild variables (evar)

---
 roverlay/packageinfo.py |   45 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index f4b7c9e..438433c 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -357,6 +357,17 @@ class PackageInfo ( object ):
 			self.set_readonly()
 	# --- end of update_now (...) ---
 
+	def update_unsafe ( self, **info ):
+		"""Updates the package info data without retrieving any locks or
+		checking writability.
+		Meant for usage with "package actions" (packagerules module).
+
+		arguments:
+		* **info --
+		"""
+		self._update ( info )
+	# --- end of update_unsafe (...) ---
+
 	def update ( self, **info ):
 		"""Uses **info to update the package info data.
 
@@ -369,13 +380,27 @@ class PackageInfo ( object ):
 			# nothing to do
 			return
 
-		initial = len ( self._info ) == 0
-
 		# remove_auto has to be the last action (keyword order is not "stable")
 		remove_auto = info.pop ( 'remove_auto', None )
 
 		self._writelock_acquire()
 
+		self._update ( info )
+
+		if remove_auto:
+			self._remove_auto ( remove_auto )
+
+		self._update_lock.release()
+	# --- end of update (**kw) ---
+
+	def _update ( self, info ):
+		"""Updates self._info using the given info dict.
+
+		arguments:
+		* info --
+		"""
+		initial = len ( self._info ) == 0
+
 		for key, value in info.items():
 
 			if key in self.__class__._UPDATE_KEYS_SIMPLE:
@@ -384,6 +409,13 @@ class PackageInfo ( object ):
 			elif initial and key in self.__class__._UPDATE_KEYS_SIMPLE_INITIAL:
 				self [key] = value
 
+			elif key[:4] == 'EVAR':
+				if 'EVAR' in self._info:
+					self._info ['EVAR'].add ( value )
+				else:
+					# set or dict?
+					self._info ['EVAR'] = set ( ( value, ) )
+
 			elif key in self.__class__._UPDATE_KEYS_FILTER_NONE:
 				if value is not None:
 					self [key] = value
@@ -416,15 +448,10 @@ class PackageInfo ( object ):
 
 			else:
 				self.logger.error (
-					"in update(): unknown info key {}!".format ( key )
+					"in _update(): unknown info key {}!".format ( key )
 				)
 		# -- end for;
-
-		if remove_auto:
-			self._remove_auto ( remove_auto )
-
-		self._update_lock.release()
-	# --- end of update (**kw) ---
+	# --- end of _update (...) ---
 
 	def _use_filename ( self, _filename ):
 		"""auxiliary method for update(**kw)


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-01-28 23:54 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-01-28 23:54 UTC (permalink / raw
  To: gentoo-commits

commit:     dc620de71cceab25dad17b7d44c4c5a5167b4956
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jan 28 22:56:05 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jan 28 23:37:04 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=dc620de7

roverlay/argutil: --manifest-implementation

Choose Manifest implementation via command line arg.
Meant for testing the portagemanifest impl.

---
 roverlay/argutil.py |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 20c5025..ceb8baa 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -250,6 +250,13 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 		**opt_in
 	)
 
+	arg (
+		'--manifest-implementation', '-M', default=argparse.SUPPRESS,
+		help="choose how Manifest files are written (ebuild(1) or portage libs)",
+		metavar="<impl>",
+		choices=frozenset (( 'ebuild', 'e', 'portage', 'p' )),
+	)
+
 	# FIXME: description of --no-incremental is not correct,
 	# --no-incremental currently means that an existing overlay won't be
 	# scanned for ebuilds (which means that ebuilds will be recreated),
@@ -348,6 +355,8 @@ def parse_argv ( command_map, **kw ):
 	if given ( 'deprule_file' ):
 		doconf ( p.deprule_file, 'DEPRES.SIMPLE_RULES.files' )
 
+	if given ( 'manifest_implementation' ):
+		doconf ( p.manifest_implementation, 'OVERLAY.manifest_implementation' )
 
 	return ( commands, p.config, conf, extra )
 # --- end of parse_argv (...) ---


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-01-28 23:54 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-01-28 23:54 UTC (permalink / raw
  To: gentoo-commits

commit:     354e0fc4600dfc235eda6d26fda48c4cc75e9905
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jan 28 21:17:57 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jan 28 23:37:04 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=354e0fc4

roverlay/strutil.py: split_whitespace() function

---
 roverlay/strutil.py |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 4bf3584..4a5ef5d 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -7,7 +7,7 @@
 """provides utility functions for string manipulation"""
 
 __all__ = [ 'ascii_filter', 'bytes_try_decode', 'fix_ebuild_name',
-	'pipe_lines', 'shorten_str', 'unquote'
+	'pipe_lines', 'shorten_str', 'unquote', 'split_whitespace',
 ]
 
 import re
@@ -17,6 +17,12 @@ _DEFAULT_ENCODINGS = ( 'utf-8', 'ascii', 'iso8859_15', 'utf-16', 'latin_1' )
 _EBUILD_NAME_ILLEGAL_CHARS            = re.compile ( "[.:]{1,}" )
 _EBUILD_NAME_ILLEGAL_CHARS_REPLACE_BY = '_'
 
+_WHITESPACE = re.compile ( '\s+' )
+
+def split_whitespace ( _str, **kwargs ):
+	return _WHITESPACE.split ( _str, **kwargs )
+# --- end of split_whitespace (...) ---
+
 def fix_ebuild_name ( name ):
 	"""Removes illegal chars from an ebuild name by replacing them with an
 	underscore char '_'.


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2013-01-28 23:54 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2013-01-28 23:54 UTC (permalink / raw
  To: gentoo-commits

commit:     1853a1c2a3f7371c9920f0c744992aac4d501944
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jan 28 21:19:12 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jan 28 23:37:04 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1853a1c2

roverlay/packageinfo: ebuild_filename, remove_auto

* new key: ebuild_filename
* update(): call _remove_auto() after processing all other keywords

---
 roverlay/packageinfo.py |   26 ++++++++++++++++++++++----
 1 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index fb1a570..f4b7c9e 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -60,6 +60,10 @@ class PackageInfo ( object ):
 	                                 no keys have been stored)
 	* _UPDATE_KEYS_FILTER_NONE    -- like _UPDATE_KEYS_SIMPLE, but stores
 	                                 key's value only if it is not None
+	* _REMOVE_KEYS_KEEP_EBUILD    -- a set of keys that will be kept when
+	                                 _remove_auto ( 'ebuild_written' ) is
+	                                 called.
+	                                 These keys must exist at this point!
 	"""
 
 	EBUILDVER_REGEX = re.compile ( '[-]{1,}' )
@@ -83,6 +87,11 @@ class PackageInfo ( object ):
 		'distdir',
 	))
 
+	_REMOVE_KEYS_KEEP_EBUILD    = frozenset ((
+		'distdir', 'desc_data', 'ebuild_file', 'version',
+		'ebuild_filename', 'package_name', 'package_filename',
+	))
+
 	def __init__ ( self, **initial_info ):
 		"""Initializes a PackageInfo.
 
@@ -281,6 +290,11 @@ class PackageInfo ( object ):
 			if ebuild_file is not None:
 				return os.path.dirname ( ebuild_file )
 
+		elif key_low == 'ebuild_filename':
+			ebuild_file = self._info ['ebuild_file']
+			if ebuild_file is not None:
+				return os.path.basename ( ebuild_file )
+
 		# end if <key matches ...>
 
 
@@ -357,6 +371,9 @@ class PackageInfo ( object ):
 
 		initial = len ( self._info ) == 0
 
+		# remove_auto has to be the last action (keyword order is not "stable")
+		remove_auto = info.pop ( 'remove_auto', None )
+
 		self._writelock_acquire()
 
 		for key, value in info.items():
@@ -393,9 +410,6 @@ class PackageInfo ( object ):
 					except KeyError:
 						pass
 
-			elif key == 'remove_auto':
-				self._remove_auto ( value )
-
 			elif key == 'make_desc_data':
 				if value:
 					self.get_desc_data()
@@ -404,6 +418,10 @@ class PackageInfo ( object ):
 				self.logger.error (
 					"in update(): unknown info key {}!".format ( key )
 				)
+		# -- end for;
+
+		if remove_auto:
+			self._remove_auto ( remove_auto )
 
 		self._update_lock.release()
 	# --- end of update (**kw) ---
@@ -481,7 +499,7 @@ class PackageInfo ( object ):
 			if ebuild_status == 'ebuild_written':
 				# selectively copying required keys to a new info dict
 
-				to_keep = ( 'distdir', 'desc_data', 'ebuild_file', 'version' )
+				to_keep = self.__class__._REMOVE_KEYS_KEEP_EBUILD
 
 				# needs python >= 2.7
 				info_new = { k : self.get ( k ) for k in to_keep }


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

commit:     8d7244bbf9dab106350e25d93cbc4efa6b4025c5
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Oct  2 10:03:40 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Oct  2 10:03:40 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=8d7244bb

actually remove --debug arg

This fixes commit 2610152acb3fcc3b73289bdd8617d6f8a3681238.

	modified:   roverlay/argutil.py

---
 roverlay/argutil.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index a990b25..20c5025 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -307,7 +307,7 @@ def parse_argv ( command_map, **kw ):
 	conf  = dict()
 	extra = dict (
 		nosync                  = p.nosync,
-		debug                   = p.debug,
+#		debug                   = p.debug,
 		show_overlay            = p.show_overlay,
 		write_overlay           = p.write_overlay,
 		print_stats             = p.stats,


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-20 11:16 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-20 11:16 UTC (permalink / raw
  To: gentoo-commits

commit:     2610152acb3fcc3b73289bdd8617d6f8a3681238
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Aug 20 11:12:17 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Aug 20 11:12:17 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2610152a

argutil: remove --debug arg (has no effect)

---
 roverlay/argutil.py |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index d3c498a..a990b25 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -262,15 +262,15 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 		action='store_false',
 	)
 
-	# TODO
-	arg (
-		'--debug',
-		help='''
-			Turn on debugging. This produces a lot of messages.
-			(TODO: has no effect).
-		''',
-		**opt_in
-	)
+#	# TODO
+#	arg (
+#		'--debug',
+#		help='''
+#			Turn on debugging. This produces a lot of messages.
+#			(TODO: has no effect).
+#		''',
+#		**opt_in
+#	)
 
 	return parser
 # --- end of get_parser (...) ---


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-13 18:07 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-13 18:07 UTC (permalink / raw
  To: gentoo-commits

commit:     aaddf097909078f6af1ca68ed53f1fe40c67bec0
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Aug 13 18:01:14 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Aug 13 18:01:14 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=aaddf097

PackageInfo, update: filter keys with value = None

Added a set simple_keys_filter_none that matches keys
that will be only be added if their value is not None.

This is required to fix an issue caused by the remote module's
package_nofail functions that unconditionally forward keywords
like src_uri_base.

---
 roverlay/packageinfo.py |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 22e87f5..244dbb7 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -314,10 +314,14 @@ class PackageInfo ( object ):
 			'ebuild',
 			'ebuild_file',
 			'physical_only',
-			'src_uri_base',
 			'src_uri',
 		))
 
+		simple_keys_filter_none = frozenset ((
+			'src_uri_base',
+			'distdir',
+		))
+
 		self._writelock_acquire()
 
 		for key, value in info.items():
@@ -325,13 +329,13 @@ class PackageInfo ( object ):
 			if key in simple_keys:
 				self [key] = value
 
+			elif key in simple_keys_filter_none:
+				if value is not None:
+					self [key] = value
+
 			elif key == 'filename':
 				self._use_filename ( value )
 
-			elif key == 'distdir':
-				if value is not None:
-					self ['distdir'] = value
-
 			elif key == 'pvr':
 				self._use_pvr ( value )
 


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-09  9:26 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-09  9:26 UTC (permalink / raw
  To: gentoo-commits

commit:     5f9961f0b8039807353dc6ec01317213360c5bdc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug  9 08:32:38 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug  9 08:32:38 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5f9961f0

argutil: --no-write, --no-incremental

* --write-overlay/--write is now enabled by default
* --no-incremental disables scanning of an existing overlay (thus allows
  to overwrite existing ebuilds)
* --deprule-file/-D accepts a directory value now
* --overlay/-O no longer implies --write

---
 roverlay/argutil.py |   59 +++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index db41204..e4afe4a 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -37,6 +37,15 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 			)
 		return d
 
+	def is_fs_file_or_dir ( value ):
+		f = os.path.abspath ( value )
+		if os.path.isdir ( f ) or os.path.isfile ( f ):
+			return f
+		else:
+			raise argparse.ArgumentTypeError (
+				"{!r} is neither a file nor a directory.".format ( value )
+			)
+
 	def couldbe_fs_dir ( value ):
 		d = os.path.abspath ( value )
 		if os.path.exists ( d ) and not os.path.isdir ( d ):
@@ -113,7 +122,8 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 		'-D', '--deprule-file', default=argparse.SUPPRESS,
 		action='append',
 		help="simple rule file. can be specified more than once.",
-		**fs_file
+		type=is_fs_file_or_dir,
+		metavar='<file|dir>',
 	)
 
 	arg (
@@ -156,28 +166,46 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 	arg (
 		'--show-overlay', '--show',
 		help="print ebuilds and metadata to console",
-		**opt_in
+		dest="show_overlay",
+		default=False,
+		action="store_true",
+	)
+
+	arg (
+		'--no-show-overlay', '--no-show',
+		help="don't print ebuilds and metadata to console (default)",
+		dest="show_overlay",
+		action="store_false",
 	)
 
 	arg (
 		'--write-overlay', '--write',
-		help="write overlay to filesystem",
-		# !! change to opt_out in future (FIXME)
-		**opt_in
+		help="write the overlay to filesystem",
+		dest="write_overlay",
+		default=True,
+		action="store_true",
+	)
+
+	arg (
+		'--no-write-overlay', '--no-write',
+		help="don't write the overlay",
+		dest="write_overlay",
+		action="store_false",
 	)
 
-	# FIXME: swap --stats with --no-stats? (=> print stats by default)
 	arg (
 		'--stats',
 		help="print some stats",
-		**opt_in
+		dest="stats",
+		default=True,
+		action="store_true",
 	)
 
 	arg (
 		'--no-stats',
 		help="don't print stats",
 		dest="stats",
-		**opt_out
+		action="store_false",
 	)
 
 	arg (
@@ -213,6 +241,18 @@ def get_parser ( command_map, default_config_file, default_command='create' ):
 		**opt_in
 	)
 
+	# FIXME: description of --no-incremental is not correct,
+	# --no-incremental currently means that an existing overlay won't be
+	# scanned for ebuilds (which means that ebuilds will be recreated),
+	# but old ebuilds won't be explicitly removed
+	arg (
+		'--no-incremental',
+		help="start overlay creation from scratch (ignore an existing overlay)",
+		dest='incremental',
+		default=True,
+		action='store_false',
+	)
+
 	# TODO
 	arg (
 		'--debug',
@@ -266,11 +306,12 @@ def parse_argv ( command_map, **kw ):
 		list_config    = p.list_config_entries,
 		force_distroot = p.force_distroot,
 		skip_manifest  = p.no_manifest,
+		incremental    = p.incremental,
 	)
 
 	if given ( 'overlay' ):
 		doconf ( p.overlay, 'OVERLAY.dir' )
-		extra ['write_overlay'] = True
+		#extra ['write_overlay'] = True
 
 	if given ( 'overlay_name' ):
 		doconf ( p.overlay_name, 'OVERLAY.name' )


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-08 23:46 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-08 23:46 UTC (permalink / raw
  To: gentoo-commits

commit:     b763fa4258340fc8081c311c7d299c944cf7484a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug  8 23:46:17 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug  8 23:46:17 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b763fa42

PackageInfo: use src_uri_base for src_uri if available

---
 roverlay/packageinfo.py |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 3262fba..5caa9ee 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -224,7 +224,12 @@ class PackageInfo ( object ):
 			return False
 
 		elif key_low == 'src_uri':
-			if 'origin' in self._info:
+			if 'src_uri_base' in self._info:
+				return \
+					self._info ['src_uri_base'] + '/' + \
+					self._info ['package_filename']
+
+			elif 'origin' in self._info:
 				return self._info ['origin'].get_src_uri (
 					self._info ['package_filename']
 				)


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-08 23:46 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-08 23:46 UTC (permalink / raw
  To: gentoo-commits

commit:     127d47e6aba69a528e7f2c9172f105c970bf8239
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug  8 23:47:01 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug  8 23:47:01 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=127d47e6

PackageInfo: accept src_uri_base key

---
 roverlay/packageinfo.py |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 5caa9ee..22e87f5 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -314,7 +314,8 @@ class PackageInfo ( object ):
 			'ebuild',
 			'ebuild_file',
 			'physical_only',
-			'src_uri'
+			'src_uri_base',
+			'src_uri',
 		))
 
 		self._writelock_acquire()


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-07  8:50 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-07  8:50 UTC (permalink / raw
  To: gentoo-commits

commit:     d0ed3e90f77542f1ba23d717f87ca850c585ec81
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Aug  7 08:48:55 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Aug  7 08:48:55 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d0ed3e90

strutil: bytes_try_decode()

---
 roverlay/strutil.py |   49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/roverlay/strutil.py b/roverlay/strutil.py
index 3228df6..4bf3584 100644
--- a/roverlay/strutil.py
+++ b/roverlay/strutil.py
@@ -6,13 +6,15 @@
 
 """provides utility functions for string manipulation"""
 
-__all__ = [ 'ascii_filter', 'fix_ebuild_name',
+__all__ = [ 'ascii_filter', 'bytes_try_decode', 'fix_ebuild_name',
 	'pipe_lines', 'shorten_str', 'unquote'
 ]
 
 import re
 
-_EBUILD_NAME_ILLEGAL_CHARS = re.compile ( "[.:]{1,}" )
+_DEFAULT_ENCODINGS = ( 'utf-8', 'ascii', 'iso8859_15', 'utf-16', 'latin_1' )
+
+_EBUILD_NAME_ILLEGAL_CHARS            = re.compile ( "[.:]{1,}" )
 _EBUILD_NAME_ILLEGAL_CHARS_REPLACE_BY = '_'
 
 def fix_ebuild_name ( name ):
@@ -88,3 +90,46 @@ def unquote ( _str, keep_going=False):
 
 	return _str
 # --- end of unquote (...) ---
+
+def bytes_try_decode (
+	byte_str,
+	encodings=_DEFAULT_ENCODINGS,
+	charwise_only=False,
+	force_decode=False
+):
+	"""Tries to decode a bytes object to str whose encoding is unknown
+	but predictable (with charwise conversion as last resort).
+	Returns byte_str if byte_str is already a str and force_decode is False,
+	else a decoded str.
+
+	arguments:
+	* byte_str      -- bytes object to decode
+	* encodings     -- encodings to try (None, str or list/iterable of str)
+	* charwise_only -- do charwise conversion only
+	* force_decode  -- decode byte_str even if it's already a str
+	"""
+	if not isinstance ( byte_str, str ):
+		if not charwise_only and encodings:
+			ret = None
+			if not isinstance ( encodings, str ):
+				try_enc = encodings
+			else:
+				try_enc = ( encodings, )
+
+			for enc in try_enc:
+				try:
+					ret = byte_str.decode ( enc )
+					break
+				except:
+					ret = None
+
+			if ret is not None:
+				return ret
+
+		ret = ""
+		for c in byte_str:
+			ret += chr ( c )
+		return ret
+	else:
+		return byte_str
+# --- end of bytes_try_decode() ---


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

commit:     1a0b951c506d40584bb2df25a975a17a832cb7e0
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug  2 15:09:32 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug  2 15:09:32 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1a0b951c

errorqueue: remove done TODO

---
 roverlay/errorqueue.py |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/roverlay/errorqueue.py b/roverlay/errorqueue.py
index 2b5135a..ba14fab 100644
--- a/roverlay/errorqueue.py
+++ b/roverlay/errorqueue.py
@@ -8,8 +8,7 @@ class ErrorQueue ( object  ):
 		self.using_threads      = using_threads
 		self.empty              = True
 		self._exceptions        = list()
-		# this error queue is able to unblock waiting queues (in future; TODO)
-		#  id -> queue [, unblocking_item:=None]
+		#  id -> queue, unblocking_item
 		self._queues_to_unblock = dict()
 
 		self._lock = threading.Lock()


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-08-01  7:25 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-08-01  7:25 UTC (permalink / raw
  To: gentoo-commits

commit:     057e5f51ae4cd402a9a80105aa1dcd8993055a77
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Aug  1 07:25:51 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Aug  1 07:25:51 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=057e5f51

digest.py

---
 roverlay/digest.py |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/roverlay/digest.py b/roverlay/digest.py
new file mode 100644
index 0000000..4ccbca2
--- /dev/null
+++ b/roverlay/digest.py
@@ -0,0 +1,35 @@
+import hashlib
+
+def md5sum_file ( fh, binary_digest=False ):
+	"""Returns the md5 sum for an already opened file."""
+	md5 = hashlib.md5()
+	blocksize = 16384
+
+	block = fh.read ( blocksize )
+	while block:
+		md5.update ( block )
+		block = fh.read ( blocksize )
+
+	return md5.digest() if binary_digest else md5.hexdigest()
+# --- end of md5sum_file (...) ---
+
+
+_DIGEST_MAP = dict (
+	md5 = md5sum_file,
+)
+
+def digest_supported ( digest_type ):
+	"""Returns True if the given digest type is supported, else False."""
+	return digest_type in _DIGEST_MAP
+# --- digest_supported (...) ---
+
+def dodigest_file ( _file, digest_type, binary_digest=False ):
+	ret = None
+	with open ( _file, mode='rb' ) as fh:
+		ret = _DIGEST_MAP [digest_type] ( fh, binary_digest=binary_digest )
+	return ret
+# --- end of dodigest_file (...) ---
+
+def digest_compare ( _file, digest, digest_type, binary_digest=False ):
+	return digest == dodigest_file ( _file, digest_type, binary_digest )
+# --- end of digest_compare (...) ---


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-31 17:51 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-31 17:51 UTC (permalink / raw
  To: gentoo-commits

commit:     847956c1d54647d0cfdbd9de2adc21d8404b82ff
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jul 31 13:57:35 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jul 31 13:57:35 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=847956c1

PackageInfo.update: reduce if-checks

use a simple_keys iterable to determine which key,value pairs can directly be
used (self._info [key] = value) instead of an if-check per key.
The logger message for unknown keys is a bit more accurate now.

---
 roverlay/packageinfo.py |   31 ++++++++++++++-----------------
 1 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 731b62c..4514d4f 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -260,32 +260,29 @@ class PackageInfo ( object ):
 			# nothing to do
 			return
 
+		simple_keys = frozenset ((
+			'origin',
+			'desc_data',
+			'ebuild',
+			'ebuild_file',
+			'physical_only',
+			'src_uri'
+		))
+
 		self._writelock_acquire()
 
 		for key, value in info.items():
 
-			if key == 'filename':
+			if key in simple_keys:
+				self [key] = value
+
+			elif key == 'filename':
 				self._use_filename ( value )
 
 			elif key == 'distdir':
 				if value is not None:
 					self ['distdir'] = value
 
-			elif key == 'origin':
-				self ['origin'] = value
-
-			elif key == 'desc_data':
-				self ['desc_data'] = value
-
-			elif key == 'ebuild':
-				self ['ebuild'] = value
-
-			elif key == 'ebuild_file':
-				self ['ebuild_file'] = value
-
-			elif key == 'physical_only':
-				self ['physical_only'] = value
-
 			elif key == 'pvr':
 				self._use_pvr ( value )
 
@@ -309,7 +306,7 @@ class PackageInfo ( object ):
 				self._remove_auto ( value )
 
 			else:
-				LOGGER.error ( "unknown info key {}!".format ( key ) )
+				LOGGER.error ( "in update(): unknown info key {}!".format ( key ) )
 
 		self._update_lock.release()
 	# --- end of update (**kw) ---


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-30  8:52 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-30  8:52 UTC (permalink / raw
  To: gentoo-commits

commit:     370d65c3ceef9ad482e13b4e9fbd98fe2a752b1a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 30 08:40:36 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 30 08:40:36 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=370d65c3

fix <str>.format() in packageinfo

---
 roverlay/packageinfo.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 07b2e77..731b62c 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -345,7 +345,7 @@ class PackageInfo ( object ):
 			# TODO: discard or continue with bad version?
 			logging.error (
 				"Cannot parse version string {!r} for {!r}".format (
-					( _filename, version_str )
+					_filename, version_str
 				)
 			)
 			raise


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-30  8:52 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-30  8:52 UTC (permalink / raw
  To: gentoo-commits

commit:     2c8f26987ba0e1fe111b45cd2d9566abb69372b9
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul 19 16:52:16 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul 19 16:52:16 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2c8f2698

packageinfo: compare_version, has_key

---
 roverlay/packageinfo.py |   34 +++++++++++++++++++++++++++++++++-
 1 files changed, 33 insertions(+), 1 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index a2910c5..f9d26d1 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -114,6 +114,38 @@ class PackageInfo ( object ):
 		return True
 	# --- end of _writelock_acquire (...) ---
 
+	def has_key ( self, *keys ):
+		for k in keys:
+			if k not in self._info:
+				# try harder - use get() with fallback value to see if value
+				# can be calculated
+				if self.get ( k, do_fallback=True ) is None:
+					return False
+		return True
+	# --- end of has_key (...) ---
+
+	has = has_key
+
+	def compare_version ( self, other_package ):
+		"""Compares the version of two PackageInfo objects.
+		Returns 1 if self's version is higher, -1 if lower and 0 if equal.
+
+		arguments:
+		* other_package --
+		"""
+		if other_package is None: return 1
+
+		my_ver    = self.get ( 'version', fallback_value=0 )
+		other_ver = other_package.get ( 'version', fallback_value=0 )
+
+		if my_ver > other_ver:
+			return 1
+		elif my_ver == other_ver:
+			return 0
+		else:
+			return -1
+	# --- end of compare_version (...) ---
+
 	def get ( self, key, fallback_value=None, do_fallback=False ):
 		"""Returns the value specified by key.
 		The value is either calculated or taken from dict self._info.
@@ -172,7 +204,7 @@ class PackageInfo ( object ):
 
 
 		# fallback
-		if do_fallback:
+		if do_fallback or fallback_value is not None:
 			return fallback_value
 
 		elif key_low in self.__class__.ALWAYS_FALLBACK:


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:overlay_wip commit in: roverlay/
@ 2012-07-24 16:59 André Erdmann
  2012-07-30  8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2012-07-24 16:59 UTC (permalink / raw
  To: gentoo-commits

commit:     6593a3562703348b5008847d92e820a75efaf921
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jul 24 16:56:54 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jul 24 16:56:54 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6593a356

PackageInfo: _remove_auto:ebuild_written, fix get

	geändert:   roverlay/packageinfo.py

---
 roverlay/packageinfo.py |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 829b798..07b2e77 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -183,8 +183,9 @@ class PackageInfo ( object ):
 				# this doesn't work if the package is in a sub directory
 				# of the repo's distdir
 				return self._info ['origin'].distdir
-			else:
+			elif 'package_file' in self._info:
 				return os.path.dirname ( self._info ['package_file'] )
+			# else fallback/KeyError
 
 		elif key_low == 'has_suggests':
 			# 'has_suggests' not in self._info -> assume False
@@ -234,6 +235,12 @@ class PackageInfo ( object ):
 	# --- end of __setitem__ (...) ---
 
 	def update_now ( self, **info ):
+		"""Updates the package info data with temporarily enabling write access.
+		Data will be readonly after calling this method.
+
+		arguments:
+		* **info --
+		"""
 		if len ( info ) == 0: return
 		with self._update_lock:
 			self.set_writeable()
@@ -374,7 +381,27 @@ class PackageInfo ( object ):
 		after entering status 'ebuild_status' (like ebuild in overlay and
 		written -> don't need the ebuild string etc.)
 		"""
-		print ( "PackageInfo._remove_auto: method stub, request ignored." )
+		with self._update_lock:
+
+			if ebuild_status == 'ebuild_written':
+				# selectively copying required keys to a new info dict
+
+				to_keep = ( 'distdir', 'desc_data', 'ebuild_file', 'version' )
+
+				# needs python >= 2.7
+				info_new = { k : self.get ( k ) for k in to_keep }
+
+				# also add an ebuild stub to the new dict (workaround, FIXME)
+				info_new ['ebuild'] = True
+
+				if 'physical_only' in self._info:
+					info_new ['physical_only'] = self._info ['physical_only']
+
+				info_old   = self._info
+				self._info = info_new
+				del info_old
+			# -- if
+		# -- lock
 	# --- end of _remove_auto (...) ---
 
 	def _use_filepath ( self, _filepath ):


^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:overlay_wip commit in: roverlay/
@ 2012-07-18 16:49 André Erdmann
  2012-07-30  8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2012-07-18 16:49 UTC (permalink / raw
  To: gentoo-commits

commit:     5cd02da17ef13323aff48dae2d5527396d298211
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jul 18 16:45:30 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jul 18 16:45:30 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5cd02da1

util, dodir: catch OSError if dir exists

---
 roverlay/util.py |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index 2df4845..3f32646 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -94,11 +94,16 @@ def sysnop ( nop_returns_success=True, format_str=None ):
 # --- end of sysnop (...) ---
 
 def dodir ( directory, mkdir_p=False, **makedirs_kw ):
-	if not os.path.isdir ( directory ):
+	if os.path.isdir ( directory ): return True
+	try:
 		if mkdir_p:
 			os.makedirs ( directory, **makedirs_kw )
 		else:
 			os.mkdir ( directory )
 
-	return True
+		return True
+	except Exception as e:
+		LOGGER.exception ( e )
+		return os.path.isdir ( directory )
+
 # --- end of dodir (...) ---



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

commit:     35073605819b2238010a284da4678d31509ab191
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 16 16:03:47 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 16 16:03:47 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=35073605

util: function to remove non-ascii chars

---
 roverlay/util.py |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index d658b15..2df4845 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -21,6 +21,11 @@ def fix_ebuild_name ( name ):
 	)
 # --- end of fix_ebuild_name (...) ---
 
+def ascii_filter ( _str ):
+	"""Removes all non-ascii chars from a string and returns the result."""
+	return ''.join ( c for c in _str if ord ( c ) < 128 )
+# --- end of ascii_filter (...) ---
+
 def shorten_str ( s, maxlen, replace_end=None ):
 	if not replace_end is None:
 		rlen = maxlen - len ( replace_end )



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

commit:     5e67a62f326f96b813e8fdd19a50d236874a41bd
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 13 10:36:53 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 13 10:36:53 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=5e67a62f

remove NopErrorQueue

---
 roverlay/errorqueue.py |   29 ++++-------------------------
 1 files changed, 4 insertions(+), 25 deletions(-)

diff --git a/roverlay/errorqueue.py b/roverlay/errorqueue.py
index d0aa042..2b5135a 100644
--- a/roverlay/errorqueue.py
+++ b/roverlay/errorqueue.py
@@ -1,33 +1,11 @@
-import sys
 import threading
 
-class _EQueue ( object ) : pass
-
-class NopErrorQueue ( _EQueue ):
-	"""This can be used as error queue in single-threaded execution."""
-	def __init__ ( self ):
-		self.empty = True
-
-	def push ( self, context, error ):
-		self.empty = False
-		sys.stderr.write ( "Exception from {!r}:\n".format ( context ) )
-		raise error
-
-	def really_empty ( self ): return self.empty
-	def attach_queue ( self, q, unblock_item ): pass
-	def remove_queue ( self, q ): pass
-	def unblock_queues ( self ): pass
-	def peek ( self ): return ( None, None )
-	def get_all ( self ): return ( ( None, None ), )
-	def get_exceptions ( self ): return ()
-
-
-#class ErrorQueue ( NopErrorQueue ):
-class ErrorQueue ( _EQueue ):
+class ErrorQueue ( object  ):
 	"""This is the error queue for threaded execution."""
 	# (it's not a queue)
 
-	def __init__ ( self ):
+	def __init__ ( self, using_threads=True ):
+		self.using_threads      = using_threads
 		self.empty              = True
 		self._exceptions        = list()
 		# this error queue is able to unblock waiting queues (in future; TODO)
@@ -65,6 +43,7 @@ class ErrorQueue ( _EQueue ):
 			self.empty = False
 			self._unblock_queues()
 
+		if not self.using_threads: raise error
 	def unblock_queues ( self ):
 		"""Unblocks all attached queues."""
 		with self._lock:



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:depres_wip commit in: roverlay/
@ 2012-07-16 16:15 André Erdmann
  2012-07-16 16:15 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
  0 siblings, 1 reply; 159+ messages in thread
From: André Erdmann @ 2012-07-16 16:15 UTC (permalink / raw
  To: gentoo-commits

commit:     f5e0ea775cc86046fc424a2c63e9709670a4fe6d
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 16 11:17:20 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 16 11:17:20 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f5e0ea77

move fix_ebuild_name to util

---
 roverlay/packageinfo.py |    9 ++-------
 roverlay/util.py        |   10 ++++++++++
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index cc09a6b..052fad7 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -41,10 +41,6 @@ class PackageInfo ( object ):
 		config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$'
 	)
 
-	ILLEGAL_NAME_CHARS = re.compile ( "[.:]{1,}" )
-	ILLEGAL_NAME_CHARS_REPLACE_BY = '_'
-
-
 	def __init__ ( self, **initial_info ):
 		"""Initializes a PackageInfo.
 
@@ -308,9 +304,8 @@ class PackageInfo ( object ):
 		#  using pkg_version for the ebuild version
 
 		# removing illegal chars from the package_name
-		ebuild_name = PackageInfo.ILLEGAL_NAME_CHARS.sub (
-			PackageInfo.ILLEGAL_NAME_CHARS_REPLACE_BY, package_name
-		)
+		ebuild_name = util.fix_ebuild_name ( package_name )
+
 		if ebuild_name != package_name:
 			self ['name'] = ebuild_name
 

diff --git a/roverlay/util.py b/roverlay/util.py
index f66532a..d658b15 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -11,6 +11,16 @@ from roverlay import config
 
 LOGGER = logging.getLogger ( 'util' )
 
+_EBUILD_NAME_ILLEGAL_CHARS = re.compile ( "[.:]{1,}" )
+_EBUILD_NAME_ILLEGAL_CHARS_REPLACE_BY = '_'
+
+def fix_ebuild_name ( name ):
+	return _EBUILD_NAME_ILLEGAL_CHARS.sub (
+		_EBUILD_NAME_ILLEGAL_CHARS_REPLACE_BY,
+		name
+	)
+# --- end of fix_ebuild_name (...) ---
+
 def shorten_str ( s, maxlen, replace_end=None ):
 	if not replace_end is None:
 		rlen = maxlen - len ( replace_end )



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

commit:     0c9efb4ddce50c2c9e94100eb77812238650d7eb
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jul 10 17:43:08 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jul 10 17:43:08 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0c9efb4d

try to run without a config file

---
 roverlay/__init__.py |    3 ++-
 roverlay/argutil.py  |    8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index 1399df0..3d1ecfa 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -27,7 +27,8 @@ def load_config_file ( cfile, extraconf=None ):
 	* extraconf -- a dict with additional config entries that will override
 	               entries read from cfile
 	"""
-	roverlay.config.loader().load_config ( cfile )
+	if cfile:
+		roverlay.config.loader().load_config ( cfile )
 
 	if extraconf is not None:
 		roverlay.config.access().merge_with ( extraconf )

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 6249644..98a0406 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -29,6 +29,12 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 			)
 		return d
 
+	def is_fs_file_or_void ( value ):
+		if value:
+			return is_fs_file ( value )
+		else:
+			return ''
+
 	parser = argparse.ArgumentParser (
 		description='\n'.join ((
 			roverlay.description_str, roverlay.license_str,
@@ -67,7 +73,7 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 		'-c', '--config',
 		default=DEFAULT_CONFIG,
 		help="config file",
-		**fs_file
+		type=is_fs_file_or_void, metavar="<file>"
 	)
 	arg (
 		'-F', '--field-definition', '--fdef', default=argparse.SUPPRESS,



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-09 17:19 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-09 17:19 UTC (permalink / raw
  To: gentoo-commits

commit:     9fd58ecaad91eb2d0bce5234c5eadc61b7904c36
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul  9 16:27:40 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul  9 16:27:40 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9fd58eca

argutil: --overlay-name and some logic

--from / --distdir now implies --nosync and create

	modified:   roverlay/argutil.py

---
 roverlay/argutil.py |   19 ++++++++++++++-----
 1 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index 4750d15..6249644 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -119,6 +119,12 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 		type=couldbe_fs_dir
 	)
 
+	arg (
+		'--overlay-name', '-N', default=argparse.SUPPRESS,
+		help="overlay name",
+		metavar="<name>",
+		dest="overlay_name"
+	)
 
 	arg (
 		'--show-overlay', '--show',
@@ -215,7 +221,7 @@ def parse_argv ( *args, **kw ):
 
 	given = lambda kw : hasattr ( p, kw )
 
-
+	commands = ( p.commands, ) if isinstance ( p.commands, str ) else p.commands
 	conf  = dict()
 	extra = dict (
 		nosync         = p.nosync,
@@ -232,6 +238,9 @@ def parse_argv ( *args, **kw ):
 		doconf ( p.overlay, 'OVERLAY.dir' )
 		extra ['write_overlay'] = True
 
+	if given ( 'overlay_name' ):
+		doconf ( p.overlay_name, 'OVERLAY.name' )
+
 	if given ( 'field_definition' ):
 		doconf ( p.field_definition, 'DESCRIPTION.field_definition_file' )
 
@@ -244,6 +253,9 @@ def parse_argv ( *args, **kw ):
 	if given ( 'distdirs' ):
 		doconf ( (), 'REPO.config_files' )
 		extra ['distdirs'] = frozenset ( p.distdirs )
+		extra ['nosync']   = True
+		# FIXME: COMMANDS are unknown here (theoretically)
+		commands.append ( "create" )
 		# FIXME:
 		# distdir implies --nosync, but LocalRepo doesn't care about that ( sync() is nosync() )
 
@@ -251,8 +263,5 @@ def parse_argv ( *args, **kw ):
 		doconf ( p.deprule_file, 'DEPRES.SIMPLE_RULES.files' )
 
 
-	return (
-		( p.commands, ) if isinstance ( p.commands, str ) else p.commands,
-		p.config, conf, extra
-	)
+	return ( commands, p.config, conf, extra )
 # --- end of parse_argv (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-04 18:21 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-04 18:21 UTC (permalink / raw
  To: gentoo-commits

commit:     f10e073c8d8e10ccd5c165a2cdc03a36da0b4470
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jul  4 18:11:28 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jul  4 18:11:28 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f10e073c

util: remove easylock decorator

	modified:   roverlay/util.py

---
 roverlay/util.py |   24 ------------------------
 1 files changed, 0 insertions(+), 24 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index cf6c018..f66532a 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -11,30 +11,6 @@ from roverlay import config
 
 LOGGER = logging.getLogger ( 'util' )
 
-def easylock ( _lock=threading.Lock() ):
-	"""This decorator locks the function while in use
-	with either the given Lock or an anonymous threading.Lock.
-
-	arguments:
-	* _lock -- lock to use, defaults to threading.Lock()
-
-	returns: wrapped function
-	"""
-	def wrapper ( f ):
-		"""Wraps the function."""
-		def _locked ( *args, **kw ):
-			"""Actual wrapper.
-			Locks _lock, calls the function and releases _lock in any case."""
-			try:
-				_lock.acquire()
-				f ( *args, **kw )
-			finally:
-				_lock.release()
-		return _locked
-
-	return wrapper
-# --- end of @easylock (<lock>) ---
-
 def shorten_str ( s, maxlen, replace_end=None ):
 	if not replace_end is None:
 		rlen = maxlen - len ( replace_end )



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-04 18:21 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-04 18:21 UTC (permalink / raw
  To: gentoo-commits

commit:     2f210f30d60427f636e477890bd0091444fafe18
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jul  4 18:11:10 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jul  4 18:11:10 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2f210f30

argutil: --stats, --no-stats

---
 roverlay/argutil.py |   40 +++++++++++++++++++++++++++++-----------
 1 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
index d1640ac..8e37694 100644
--- a/roverlay/argutil.py
+++ b/roverlay/argutil.py
@@ -89,7 +89,6 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 		**fs_file
 	)
 
-
 	arg (
 		'--distdir', '--from', default=argparse.SUPPRESS,
 		action='append',
@@ -99,6 +98,7 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 			ebuilds.
 		''',
 		metavar="<DISTDIR>",
+		dest='distdirs',
 		type=is_fs_dir
 	)
 
@@ -113,37 +113,52 @@ def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
 	)
 
 	arg (
-		'--show',
+		'--show-overlay', '--show',
 		help="print ebuilds and metadata to console",
 		**opt_in
 	)
 
 	arg (
-		'--write',
+		'--write-overlay', '--write',
 		help="write overlay to filesystem",
-		# !! change to opt_out (FIXME)
+		# !! change to opt_out in future (FIXME)
 		**opt_in
 	)
 
+	# FIXME: swap --stats with --no-stats? (=> print stats by default)
+	arg (
+		'--stats',
+		help="print some stats",
+		**opt_in
+	)
+
+	arg (
+		'--no-stats',
+		help="don't print stats",
+		dest="stats",
+		**opt_out
+	)
 
 	arg (
 		'--nosync', '--no-sync',
-		help="disable syncing with remotes (offline mode). TODO",
+		help="disable syncing with remotes (offline mode).",
 		**opt_in
 	)
+
 	arg (
 		'--force-distroot',
-		help="always use <DISTROOT>/<repo name> as repo distdir. TODO.",
+		help="always use <DISTROOT>/<repo name> as repo distdir.",
 		**opt_in
 	)
 
+	# TODO
 	arg (
 		'--debug',
 		help='''
 			Turn on debugging. This produces a lot of messages.
 			(TODO: always on).
 		''',
-		**opt_out
+		**opt_in
 	)
 
 	return parser
@@ -181,9 +196,10 @@ def parse_argv ( *args, **kw ):
 	conf  = dict()
 	extra = dict (
 		nosync         = p.nosync,
-		show           = p.show,
-		write          = p.write,
 		debug          = p.debug,
+		show_overlay   = p.show_overlay,
+		write_overlay  = p.write_overlay,
+		print_stats    = p.stats,
 		force_distroot = p.force_distroot,
 	)
 
@@ -196,9 +212,11 @@ def parse_argv ( *args, **kw ):
 	if given ( 'distroot' ):
 		doconf ( p.distroot, 'distfiles.root' )
 
-	if given ( 'distdir' ):
+	if given ( 'distdirs' ):
 		doconf ( (), 'REPO.config_files' )
-		extra ['distdir'] = p.distdir
+		extra ['distdirs'] = frozenset ( p.distdirs )
+		# FIXME:
+		# distdir implies --nosync, but LocalRepo doesn't care about that ( sync() is nosync() )
 
 	if given ( 'deprule_file' ):
 		doconf ( p.deprule_file, 'DEPRES.SIMPLE_RULES.files' )



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-07-03 17:48 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-07-03 17:48 UTC (permalink / raw
  To: gentoo-commits

commit:     6485e56521930bb59e4fdcdddc015286aa6c874b
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jul  3 17:45:55 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jul  3 17:45:55 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6485e565

roverlay/argutil (using argparse)

this sets up an ArgParser suitable for roverlay scripts

	new file:   roverlay/argutil.py

---
 roverlay/argutil.py |  211 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 211 insertions(+), 0 deletions(-)

diff --git a/roverlay/argutil.py b/roverlay/argutil.py
new file mode 100644
index 0000000..d1640ac
--- /dev/null
+++ b/roverlay/argutil.py
@@ -0,0 +1,211 @@
+
+import os.path
+import argparse
+import roverlay
+
+def get_parser ( CMD_DESC, DEFAULT_CONFIG ):
+
+	def is_fs_file ( value ):
+		f = os.path.abspath ( value )
+		if not os.path.isfile ( f ):
+			raise argparse.ArgumentTypeError (
+				"%r is not a file." % value
+			)
+		return f
+
+	def is_fs_dir ( value ):
+		d = os.path.abspath ( value )
+		if not os.path.isdir ( d ):
+			raise argparse.ArgumentTypeError (
+				"%r is not a directory." % value
+			)
+		return d
+
+	def couldbe_fs_dir ( value ):
+		d = os.path.abspath ( value )
+		if os.path.exists ( d ) and not os.path.isdir ( d ):
+			raise argparse.ArgumentTypeError (
+				"%r cannot be a directory." % value
+			)
+		return d
+
+	parser = argparse.ArgumentParser (
+		description='\n'.join ((
+			roverlay.description_str, roverlay.license_str,
+		)),
+		epilog = 'Known commands:\n' + '\n'.join (
+			( ( '* ' + c ).ljust(17) + ' - ' + d for (c,d) in CMD_DESC.items() )
+		),
+		add_help=True,
+		formatter_class=argparse.RawDescriptionHelpFormatter,
+		)
+
+	arg     = parser.add_argument
+	opt_in  = dict ( default=False, action='store_true' )
+	opt_out = dict ( default=True,  action='store_false' )
+
+	fs_file = dict ( type=is_fs_file, metavar="<file>" )
+
+	# adding args starts here
+
+	arg (
+		'-V', '--version', action='version', version=roverlay.version_str
+	)
+
+	arg (
+		'commands',
+		# fixme: CMD_DESC is "unknown", but default is set to a specific command
+		default='create',
+		help="action to perform. choices are " + ', '.join (CMD_DESC.keys()) + \
+			". defaults to %(default)s.",
+		nargs="*",
+		choices=CMD_DESC.keys(),
+		metavar="command"
+	)
+
+	arg (
+		'-c', '--config',
+		default=DEFAULT_CONFIG,
+		help="config file",
+		**fs_file
+	)
+	arg (
+		'-F', '--field-definition', '--fdef', default=argparse.SUPPRESS,
+		help="field definition file",
+		**fs_file
+	)
+
+	arg (
+		'-R', '--repo-config', default=argparse.SUPPRESS,
+		action='append',
+		help="repo config file.",
+		**fs_file
+	)
+
+	arg (
+		'-D', '--deprule-file', default=argparse.SUPPRESS,
+		action='append',
+		help="simple rule file. can be specified more than once.",
+		**fs_file
+	)
+
+
+	arg (
+		'--distdir', '--from', default=argparse.SUPPRESS,
+		action='append',
+		help='''
+			use packages from %(metavar)s for ebuild creation (ignore all repos).
+			only useful for testing 'cause SRC_URI will be invalid in the created
+			ebuilds.
+		''',
+		metavar="<DISTDIR>",
+		type=is_fs_dir
+	)
+
+	arg (
+		'--distroot', default=argparse.SUPPRESS,
+		help='''
+			use %(metavar)s as distdir root for repos
+			that don't define their own package dir.
+		''',
+		metavar="<DISTROOT>",
+		type=couldbe_fs_dir
+	)
+
+	arg (
+		'--show',
+		help="print ebuilds and metadata to console",
+		**opt_in
+	)
+
+	arg (
+		'--write',
+		help="write overlay to filesystem",
+		# !! change to opt_out (FIXME)
+		**opt_in
+	)
+
+
+	arg (
+		'--nosync', '--no-sync',
+		help="disable syncing with remotes (offline mode). TODO",
+		**opt_in
+	)
+	arg (
+		'--force-distroot',
+		help="always use <DISTROOT>/<repo name> as repo distdir. TODO.",
+		**opt_in
+	)
+
+	arg (
+		'--debug',
+		help='''
+			Turn on debugging. This produces a lot of messages.
+			(TODO: always on).
+		''',
+		**opt_out
+	)
+
+	return parser
+# --- end of get_parser (...) ---
+
+def parse_argv ( *args, **kw ):
+	"""Parses sys.argv and returns the result as tuple
+	(<commands to run>, <config file>,
+	<dict for config>, <extra options as dict>).
+
+	All args/keywords are passed to get_parser().
+	Passes all exceptions.
+	"""
+	def doconf ( value, path ):
+		pos = conf
+		if isinstance ( path, str ):
+			path = path.split ( '.' )
+		last = len ( path ) - 1
+		for i, k in enumerate ( path ):
+			if i == last:
+				pos [k.lower()] = value
+			else:
+				k = k.upper()
+				if not k in pos:
+					pos [k] = dict()
+
+				pos = pos [k]
+
+
+	p = get_parser ( *args, **kw ).parse_args()
+
+	given = lambda kw : hasattr ( p, kw )
+
+
+	conf  = dict()
+	extra = dict (
+		nosync         = p.nosync,
+		show           = p.show,
+		write          = p.write,
+		debug          = p.debug,
+		force_distroot = p.force_distroot,
+	)
+
+	if given ( 'field_definition' ):
+		doconf ( p.field_definition, 'DESCRIPTION.field_definition_file' )
+
+	if given ( 'repo_config' ):
+		doconf ( p.repo_config, 'REPO.config_files' )
+
+	if given ( 'distroot' ):
+		doconf ( p.distroot, 'distfiles.root' )
+
+	if given ( 'distdir' ):
+		doconf ( (), 'REPO.config_files' )
+		extra ['distdir'] = p.distdir
+
+	if given ( 'deprule_file' ):
+		doconf ( p.deprule_file, 'DEPRES.SIMPLE_RULES.files' )
+
+
+	return (
+		( p.commands, ) if isinstance ( p.commands, str ) else p.commands,
+		p.config, conf, extra
+	)
+# --- end of parse_argv (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-28 13:29 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-28 13:29 UTC (permalink / raw
  To: gentoo-commits

commit:     d1789f1570486f0ac5f52804801de7f078d0991f
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 28 13:28:59 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 28 13:28:59 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d1789f15

PackageInfo: fix illegal ebuild names

	modified:   roverlay/packageinfo.py

---
 roverlay/packageinfo.py |   15 +++++++++++++--
 1 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 8f59439..cc09a6b 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -41,6 +41,10 @@ class PackageInfo ( object ):
 		config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$'
 	)
 
+	ILLEGAL_NAME_CHARS = re.compile ( "[.:]{1,}" )
+	ILLEGAL_NAME_CHARS_REPLACE_BY = '_'
+
+
 	def __init__ ( self, **initial_info ):
 		"""Initializes a PackageInfo.
 
@@ -296,13 +300,20 @@ class PackageInfo ( object ):
 			# TODO: discard or continue with bad version?
 			logging.error (
 				"Cannot parse version string '%s' for '%s'"
-					% ( filepath, version_str )
+					% ( _filename, version_str )
 			)
 			raise
 
 		# using package name as name (unless modified later),
 		#  using pkg_version for the ebuild version
-		self ['name']             = package_name
+
+		# removing illegal chars from the package_name
+		ebuild_name = PackageInfo.ILLEGAL_NAME_CHARS.sub (
+			PackageInfo.ILLEGAL_NAME_CHARS_REPLACE_BY, package_name
+		)
+		if ebuild_name != package_name:
+			self ['name'] = ebuild_name
+
 		self ['ebuild_verstr']    = version_str
 
 		# for DescriptionReader



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-26 15:42 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-26 15:42 UTC (permalink / raw
  To: gentoo-commits

commit:     10cd6f63877dd53d3e19c371ea246de9f2fd1238
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jun 26 15:40:41 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jun 26 15:40:41 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=10cd6f63

extend PackageInfo

* distdir can now be stored in _info

	modified:   roverlay/packageinfo.py

---
 roverlay/packageinfo.py |   41 ++++++++++++++++++++---------------------
 1 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index fdce322..8f59439 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -143,12 +143,14 @@ class PackageInfo ( object ):
 		elif key_low == 'package_file':
 			# assuming that origin is in self._info
 			return os.path.join (
-				self._info ['origin'].distdir,
+				self.get ( 'distdir' ),
 				self._info ['package_filename']
 			)
 
 		elif key_low == 'distdir':
 			if 'origin' in self._info:
+				# this doesn't work if the package is in a sub directory
+				# of the repo's distdir
 				return self._info ['origin'].distdir
 			else:
 				return os.path.dirname ( self._info ['package_file'] )
@@ -209,6 +211,7 @@ class PackageInfo ( object ):
 	# --- end of __setitem__ (...) ---
 
 	def update_now ( self, **info ):
+		if len ( info ) == 0: return
 		with self._update_lock:
 			self.set_writeable()
 			self.update ( **info )
@@ -223,33 +226,38 @@ class PackageInfo ( object ):
 
 		raises: Exception when readonly
 		"""
-		if len ( info ) == 0 :
+		if len ( info ) == 0:
 			# nothing to do
 			return
 
 		self._writelock_acquire()
 
 		for key, value in info.items():
-			if key == 'desc' or key == 'desc_data':
-				self ['desc_data'] = value
-
-			elif key == 'ebuild':
-				self ['ebuild'] = value
 
-			elif key == 'filepath':
-				self._use_filepath ( value )
-
-			elif key == 'filename':
+			if key == 'filename':
 				self._use_filename ( value )
 
+			elif key in ( 'package_dir', 'dirpath', 'distdir' ):
+				if value is not None:
+					self ['distdir'] = value
+
 			elif key == 'origin':
 				self ['origin'] = value
 
+			elif key == 'desc' or key == 'desc_data':
+				self ['desc_data'] = value
+
+			elif key == 'ebuild':
+				self ['ebuild'] = value
+
 			elif key == 'suggests':
 				self ['has_suggests'] = value
 
 			elif key == 'depres_results' or key == 'depres_result':
-				self._use_depres_result ( value )
+				self ['has_suggests'] = value [2]
+
+			elif key == 'filepath':
+				self._use_filepath ( value )
 
 			else:
 				LOGGER.warning ( "unknown info key %s!" % key )
@@ -317,15 +325,6 @@ class PackageInfo ( object ):
 		self._use_filename ( os.path.basename ( filepath ) )
 	# --- end of _use_filepath (...) ---
 
-	def _use_depres_result ( self, result ):
-		"""auxiliary method for update(**kw)
-
-		arguments:
-		* result --
-		"""
-		self ['has_suggests'] = result [2]
-	# --- end of _use_depres_result (...) ---
-
 	def __str__ ( self ):
 		return "<PackageInfo for %s>" % self.get (
 			'package_file', fallback_value='[unknown file]', do_fallback=True



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-25 18:19 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-25 18:19 UTC (permalink / raw
  To: gentoo-commits

commit:     edd8719acc718698e597ff4cebe52aa520237d17
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun 25 18:12:07 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun 25 18:12:07 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=edd8719a

extend PackageInfo

---
 roverlay/packageinfo.py |   80 +++++++++++++++++++++++++++++++---------------
 1 files changed, 54 insertions(+), 26 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index 712b5a6..fdce322 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -136,19 +136,22 @@ class PackageInfo ( object ):
 			return self._info [key_low]
 
 		# 'virtual' keys - calculate result
-		elif key_low == 'distdir':
-			if 'package_dir' in self._info:
-				return self._info ['package_dir']
-
-			elif 'package_file' in self._info:
-				return os.path.dirname ( self._info ['package_file'] )
+		elif key_low == 'name':
+			# no special name, using package_name
+			return self._info ['package_name']
+
+		elif key_low == 'package_file':
+			# assuming that origin is in self._info
+			return os.path.join (
+				self._info ['origin'].distdir,
+				self._info ['package_filename']
+			)
 
-			#elif 'origin' in self._info:
+		elif key_low == 'distdir':
+			if 'origin' in self._info:
+				return self._info ['origin'].distdir
 			else:
-				return os.path.join (
-					config.get_or_fail ( ['DISTFILES', 'root' ] ),
-					self._info ['origin']
-				)
+				return os.path.dirname ( self._info ['package_file'] )
 
 		elif key_low == 'has_suggests':
 			if 'has_suggests' in self._info:
@@ -164,9 +167,17 @@ class PackageInfo ( object ):
 			# comment from ebuild:
 			## calculate SRC_URI using self._data ['origin'],
 			## either here or in eclass
-			return "http://TODO!!!/" + self._info ['package_filename']
+
 			#return "**packageinfo needs information from sync module!"
 
+			if 'origin' in self._info:
+				return self._info ['origin'].get_src_uri (
+					self._info ['package_filename']
+				)
+			else:
+				return "http://localhost/R-packages/" + \
+					self._info ['package_filename']
+
 
 		# fallback
 		if do_fallback:
@@ -228,6 +239,9 @@ class PackageInfo ( object ):
 			elif key == 'filepath':
 				self._use_filepath ( value )
 
+			elif key == 'filename':
+				self._use_filename ( value )
+
 			elif key == 'origin':
 				self ['origin'] = value
 
@@ -243,16 +257,13 @@ class PackageInfo ( object ):
 		self._update_lock.release()
 	# --- end of update (**kw) ---
 
-	def _use_filepath ( self, _filepath ):
+	def _use_filename ( self, _filename ):
 		"""auxiliary method for update(**kw)
 
 		arguments:
-		* _filepath --
+		* _filename --
 		"""
-
-		filepath = os.path.abspath ( _filepath )
-
-		filename_with_ext = os.path.basename ( filepath )
+		filename_with_ext = _filename
 
 		# remove .tar.gz .tar.bz2 etc.
 		filename = PackageInfo.PKGSUFFIX_REGEX.sub ( '', filename_with_ext )
@@ -281,25 +292,42 @@ class PackageInfo ( object ):
 			)
 			raise
 
-
-
 		# using package name as name (unless modified later),
 		#  using pkg_version for the ebuild version
 		self ['name']             = package_name
 		self ['ebuild_verstr']    = version_str
 
-
 		# for DescriptionReader
-		self ['package_file']     = filepath
 		self ['package_name']     = package_name
 
 		self ['package_filename'] = filename_with_ext
+	# --- end of _use_filename (...) ---
 
-		# keys never used (FIXME remove or use)
-		#self ['filename']        = filename
-		#self ['filepath']        = filepath
-		#self ['package_version'] = package_version
+	def _use_filepath ( self, _filepath ):
+		"""auxiliary method for update(**kw)
+
+		arguments:
+		* _filepath --
+		"""
+		LOGGER.info (
+			'Please note that _use_filepath is only meant for testing.'
+		)
+		filepath = os.path.abspath ( _filepath )
+		self ['package_file'] = filepath
+		self._use_filename ( os.path.basename ( filepath ) )
 	# --- end of _use_filepath (...) ---
 
 	def _use_depres_result ( self, result ):
+		"""auxiliary method for update(**kw)
+
+		arguments:
+		* result --
+		"""
 		self ['has_suggests'] = result [2]
+	# --- end of _use_depres_result (...) ---
+
+	def __str__ ( self ):
+		return "<PackageInfo for %s>" % self.get (
+			'package_file', fallback_value='[unknown file]', do_fallback=True
+		)
+	# --- end of __str__ (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-21 16:55 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-21 16:55 UTC (permalink / raw
  To: gentoo-commits

commit:     13bd52f447bf3884e12c97790a0f656fa786f254
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 21 16:50:28 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 21 16:50:28 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=13bd52f4

use os.path.abspath in PackageInfo.update()

	modified:   roverlay/packageinfo.py

---
 roverlay/packageinfo.py |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index fd89a60..712b5a6 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -243,13 +243,15 @@ class PackageInfo ( object ):
 		self._update_lock.release()
 	# --- end of update (**kw) ---
 
-	def _use_filepath ( self, filepath ):
+	def _use_filepath ( self, _filepath ):
 		"""auxiliary method for update(**kw)
 
 		arguments:
-		* filepath --
+		* _filepath --
 		"""
 
+		filepath = os.path.abspath ( _filepath )
+
 		filename_with_ext = os.path.basename ( filepath )
 
 		# remove .tar.gz .tar.bz2 etc.



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-20 19:03 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-20 19:03 UTC (permalink / raw
  To: gentoo-commits

commit:     b284ff8e4424dac8315bccd94319d0298ddfa2bc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun 20 18:56:42 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun 20 18:56:42 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b284ff8e

temporarily increasing console log level

---
 roverlay/__init__.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index 9ff69f7..b0478ec 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -20,7 +20,7 @@ logging.basicConfig (
 
 # add console output to the logger
 ch = logging.StreamHandler()
-ch.setLevel ( logging.INFO )
+ch.setLevel ( logging.DEBUG )
 ch.setFormatter (
 	logging.Formatter  ( '%(levelname)-8s %(name)-14s -- %(message)s' )
 )



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-20 19:03 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-20 19:03 UTC (permalink / raw
  To: gentoo-commits

commit:     ad124d77c6201deb37e4e49e140805cdfa7f78f4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun 20 10:39:14 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun 20 10:39:14 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ad124d77

utily.py fix + code removed

* removed get_distdir(), replaced by PackageInfo ['DISTDIR']
* fixed sysnop()

	modified:   roverlay/util.py

---
 roverlay/util.py |   26 +-------------------------
 1 files changed, 1 insertions(+), 25 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index bf47aa7..c697521 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -52,30 +52,6 @@ def pipe_lines ( _pipe, use_filter=False, filter_func=None ):
 		return lines
 # --- end of pipe_lines (...) ---
 
-def get_distdir ( repo_name='' ):
-	"""
-	Returns the DISTDIR for repo_name or the DISTDIR root if repo_name is empty.
-
-	arguments:
-	* repo_name --
-	"""
-
-	if len ( repo_name ) > 0:
-		distdir = config.get (
-			[ 'DISTFILES', 'REPO', repo_name ],
-			fallback_value=None
-		)
-		if distdir is None:
-			distdir = os.path.join (
-				config.get_or_fail ( [ 'DISTFILES', 'root' ] ),
-				repo_name
-			)
-	else:
-		distdir = config.get_or_fail ( [ 'DISTFILES', 'root' ] )
-
-	return distdir
-
-
 def keepenv ( *to_keep ):
 	"""Selectively imports os.environ.
 
@@ -111,7 +87,7 @@ def keepenv ( *to_keep ):
 # --- end of keepenv (...) ---
 
 def sysnop ( nop_returns_success=True, format_str=None ):
-	if returns_success:
+	if nop_returns_success:
 		candidates = ( '/bin/true', '/bin/echo' )
 	else:
 		candidates = ( '/bin/false' )



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-18 16:27 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-18 16:27 UTC (permalink / raw
  To: gentoo-commits

commit:     e0aa9e6aabfb7f705ded47d789051e1c75e9c670
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun 18 16:20:14 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun 18 16:20:14 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=e0aa9e6a

roverlay/util: dodir

	modified:   roverlay/util.py

---
 roverlay/util.py |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index cb4f6bb..bf47aa7 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -125,3 +125,9 @@ def sysnop ( nop_returns_success=True, format_str=None ):
 
 	return None
 # --- end of sysnop (...) ---
+
+def dodir ( *directories ):
+	for d in directories:
+		if not os.path.isdir ( d ):
+			os.mkdir ( d )
+# --- end of dodir (...) ---



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

commit:     b556769cc6a68d3dfc77e66d1ee5cf498177e56a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun 15 20:16:11 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun 15 20:16:11 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b556769c

config: fixes/enhancements

* config_path simpler now
* added ConfigTree.visualize() which can be used
  to print/output the config tree
* added fs_abs

	modified:   roverlay/config.py

---
 roverlay/config.py |  108 +++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 90 insertions(+), 18 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index b1710f9..dbcdfe7 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -25,6 +25,15 @@ def access():
 	return ConfigTree() if ConfigTree.instance is None else ConfigTree.instance
 # --- end of access (...) ---
 
+def get_config_path ( key ):
+	"""Creates a config path for key."""
+	_path = key.split ( '.' ) if isinstance ( key, str ) else key
+	if isinstance ( _path, ( list, tuple ) ):
+		# config paths are [ CAPSLOCK, CAPSLOCK,.... , lowercase item ]
+		return [ x.lower() if x == _path [-1] else x.upper() for x in _path ]
+	else:
+		return _path
+# --- end of get_config_path (...) ---
 
 def get ( key, fallback_value=None, fail_if_unset=False ):
 	"""Searches for key in the ConfigTree and returns its value if possible,
@@ -87,15 +96,17 @@ class ConfigTree ( object ):
 	# ** int     -- integer
 	# ** yesno   -- value must evaluate to 'yes' or 'no' (on,off,y,n,1,0...)
 	# ** fs_path -- ~ will be expanded
-	# ** fs_dir  -- fs_path and value must be a dir if it exists
-	# ** fs_file -- fs_path and value must be a file if it exists
+	# ** fs_abs  -- fs_path and path will be converted into an absolute one
+	#                (pwd + path)
+	# ** fs_dir  -- fs_abs and value must be a dir if it exists
+	# ** fs_file -- fs_abs and value must be a file if it exists
 	# TODO** fs_prog -- fs_file (and fs_path) and value must be executable (TODO)
 	# ** regex   -- value is a regex and will be compiled (re.compile(..))
 	#
 	#   multiple types are generally not supported ('this is an int or a str'),
-	#   but subtypes are (list of yesno), which can be specified by either
+	#   but subtypes are ('list of yesno'), which can be specified by either
 	#   using a list of types ['list', 'yesno'] or by separating the types
-	#   with a colon list:yesno, which is parsed in a left-to-right order.
+	#   with a colon 'list:yesno', which is parsed in a left-to-right order.
 	#   Nested subtypes such as list:slist:int:fs_file:list may lead to errors.
 	#
 	CONFIG_ENTRY_MAP = dict (
@@ -105,7 +116,7 @@ class ConfigTree ( object ):
 		),
 		log_file = dict (
 			# setting path to LOG.FILE.main to avoid collision with LOG.FILE.*
-			path       = [ 'LOG', 'FILE', 'main' ],
+			path       = [ 'LOG', 'FILE', 'Main' ],
 			value_type = 'fs_file',
 		),
 		log_file_resolved = dict (
@@ -160,7 +171,9 @@ class ConfigTree ( object ):
 	# --- end of __init__ (...) ---
 
 
-	def _findpath ( self, path, root=None, create=False, value=None ):
+	def _findpath ( self, path,
+		root=None, create=False, value=None, forcepath=False, forceval=False
+	):
 		"""All-in-one method that searches for a config path.
 		It is able to create the path if non-existent and to assign a
 		value to it.
@@ -173,11 +186,16 @@ class ConfigTree ( object ):
 		* value  -- assign value to the last path element
 		             an empty dict will be created if this is None and
 		             create is True
+		* forcepath -- if set and True: do not 'normalize' path if path is a list
+		* forceval  -- if set and True: accept None as value
 		"""
 		if path is None:
 			return root
-		elif isinstance ( path, str ):
-			path = path.split ( '.' ) if path else []
+		elif isinstance ( path, ( list, tuple ) ) and forcepath:
+			pass
+		else:
+			path = get_config_path ( path )
+
 
 		config_position = self._config if root is None else root
 
@@ -186,7 +204,7 @@ class ConfigTree ( object ):
 		for k in path:
 			if len (k) == 0:
 				continue
-			if k == path [-1] and not value is None:
+			if k == path [-1] and ( forceval or not value is None ):
 				# overwrite entry
 				config_position [k] = value
 			elif not k in config_position:
@@ -201,7 +219,7 @@ class ConfigTree ( object ):
 
 	# --- end of _findpath (...) ---
 
-	def inject ( self, key, value, suppress_log=False ):
+	def inject ( self, key, value, suppress_log=False, **kw_extra ):
 		"""This method offer direct write access to the ConfigTree. No checks
 		will be performed, so make sure you know what you're doing.
 
@@ -211,6 +229,7 @@ class ConfigTree ( object ):
 		          if a path component is missing ('<root>.<new>.<entry> creates
 		          root, new and entry if required)
 		* value -- value to be assigned
+		* **kw_extra -- extra keywords for _findpath, e.g. forceval=True
 
 		returns: None (implicit)
 		"""
@@ -223,7 +242,7 @@ class ConfigTree ( object ):
 			else:
 				self.logger.debug ( msg )
 
-		self._findpath ( key, create=True, value=value )
+		self._findpath ( key, create=True, value=value, **kw_extra )
 	# --- end of inject (...) ---
 
 	def get ( self, key, fallback_value=None, fail_if_unset=False ):
@@ -320,6 +339,14 @@ class ConfigTree ( object ):
 				return os.path.expanduser ( val ) if val else None
 			# --- end of fs_path (...) ---
 
+			def fs_abs ( val ):
+				"""val is a filesystem path - returns absolute + expanded path."""
+				if val:
+					return os.path.abspath ( os.path.expanduser ( val ) )
+				else:
+					return None
+
+
 			def fs_file ( val ):
 				""""val is a file - returns expanded path if it is
 				an existent file or it does not exist.
@@ -327,8 +354,8 @@ class ConfigTree ( object ):
 				arguments:
 				* val --
 				"""
-				if val:
-					retval = os.path.expanduser ( val )
+				retval = fs_abs ( val )
+				if retval:
 					if os.path.isfile ( retval ) or not os.path.exists ( retval ):
 						return retval
 
@@ -342,8 +369,8 @@ class ConfigTree ( object ):
 				arguments:
 				* val --
 				"""
-				if val:
-					retval = os.path.expanduser ( val )
+				retval = fs_abs ( val )
+				if retval:
 					if os.path.isdir ( retval ) or not os.path.exists ( retval ):
 						return retval
 
@@ -439,9 +466,9 @@ class ConfigTree ( object ):
 			if 'path' in cref:
 				path = cref ['path']
 			else:
-				path = low_option.split ( '_' )
-				for n in range ( len ( path ) - 1 ):
-					path [n] = path [n].upper()
+				path = option.split ( '_' )
+
+			path = get_config_path ( path )
 
 			# need a valid path
 			if path:
@@ -630,3 +657,48 @@ class ConfigTree ( object ):
 		return fdef
 
 	# --- end of _make_field_definition (...) ---
+
+
+	def _tree_to_str ( self, root, name, level=0 ):
+		"""Returns string representation of a config tree rooted at root.
+		Uses recursion (DFS).
+
+		arguments:
+		* root  -- config 'root', is a value (config 'leaf') or a dict ('tree')
+		* name  --
+		* level --
+
+		returns: string representation of the given root
+		"""
+
+		indent = level * ' '
+		var_indent =  indent + '* '
+		if root is None:
+			return "%s%s is unset\n" % ( var_indent, name )
+		elif len ( root ) == 0:
+			return "%s%s is empty\n" % ( var_indent, name )
+		elif isinstance ( root, dict ):
+			extra = ''.join ( [
+				self._tree_to_str ( n, r, level+1 ) for r, n in root.items()
+			] )
+			return "%s%s {\n%s%s}\n" % ( indent, name, extra, indent )
+		else:
+			return "%s%s = '%s'\n" % ( var_indent, name, root )
+	# --- end of _tree_to_str (...) ---
+
+	def visualize ( self, into=None ):
+		"""Visualizes the ConfigTree,
+		either into a file-like object or as return value.
+
+		arguments:
+		* into -- if not None: write into file
+
+		returns: string if into is None, else None (implicit)
+		"""
+		_vis = self._tree_to_str ( self._config, 'ConfigTree', level=0 )
+		if into is None:
+			return _vis
+		else:
+			into.write ( _vis )
+	# --- end of visualize (...) ---
+



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

commit:     f21c2a9af227ff9916cd12e1b5f976ddcd350ceb
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun 15 09:50:52 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun 15 09:50:52 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f21c2a9a

fix config

---
 roverlay/config.py |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index abef63f..b1710f9 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -36,9 +36,13 @@ def get ( key, fallback_value=None, fail_if_unset=False ):
 	* fallback_value --
 	"""
 	if not fallback_value is None:
-		return access().get ( key, fallback_value, fail_if_unset )
+		return access().get (
+			key, fallback_value=fallback_value, fail_if_unset=fail_if_unset
+		)
 	else:
-		return access().get ( key, fail_if_unset )
+		return access().get (
+			key, fallback_value=None, fail_if_unset=fail_if_unset
+		)
 # --- end of get (...) ---
 
 def get_or_fail ( key ):
@@ -180,6 +184,8 @@ class ConfigTree ( object ):
 		if config_position is None: return None
 
 		for k in path:
+			if len (k) == 0:
+				continue
 			if k == path [-1] and not value is None:
 				# overwrite entry
 				config_position [k] = value



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

commit:     6bd75daf93e1efbe1372dc908cd998a2a96299d3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun 15 09:51:28 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun 15 09:51:28 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6bd75daf

add get_distdir() to util

---
 roverlay/util.py |   23 +++++++++++++++++++----
 1 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index 6547906..12561f7 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -50,15 +50,21 @@ def get_packageinfo ( filepath ):
 # --- end of get_packageinfo (...) ---
 
 def get_extra_packageinfo ( package_info, name ):
-	return dict (
-		PKG_DISTDIR = os.path.dirname ( package_info ['package_file'] ),
-		EBUILD_FILE = os.path.join (
+	#name = name.upper()
+	ret = None
+	if name == 'PKG_DISTDIR':
+		ret = PKG_DISTDIR = os.path.dirname ( package_info ['package_file'] )
+	elif name == 'EBUILD_FILE':
+		ret = os.path.join (
 			config.get_or_fail ( [ 'OVERLAY', 'dir' ] ),
 			config.get_or_fail ( [ 'OVERLAY', 'category' ] ),
 			package_info [ 'ebuild_filename'].partition ( '-' ) [0],
 			package_info [ 'ebuild_filename'] + ".ebuild"
 		)
-	) [name]
+	else:
+		raise Exception ( "unknown package info requested." )
+
+	return ret
 # --- end of get_extra_packageinfo (...) ---
 
 def pipe_lines ( _pipe, use_filter=False, filter_func=None ):
@@ -69,6 +75,15 @@ def pipe_lines ( _pipe, use_filter=False, filter_func=None ):
 		return lines
 # --- end of pipe_lines (...) ---
 
+def get_distdir ( repo_name='' ):
+	distdir = config.get ( [ 'DISTFILES', 'REPO', repo_name ], fallback_value=None )
+	if distdir is None:
+		distdir = config.get_or_fail ( [ 'DISTFILES', 'root' ] )
+		if len ( repo_name ) > 0:
+			distdir = os.path.join ( distdir, repo_name )
+
+	return distdir
+
 
 def keepenv ( *to_keep, local_env=None ):
 	if local_env is None:



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

commit:     e5daa9e9b0f12ba38b98c806d3029a429c02b3e4
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 14 18:51:51 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 14 18:51:51 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=e5daa9e9

add OVERLAY.dir to const

---
 roverlay/const.py |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/roverlay/const.py b/roverlay/const.py
index 7ab1891..0ab36f9 100644
--- a/roverlay/const.py
+++ b/roverlay/const.py
@@ -27,7 +27,10 @@ _CONSTANTS = dict (
 			'',
 			'inherit R-packages'
 		],
-	)
+	),
+	OVERLAY = dict (
+		category = 'sci-R',
+	),
 )
 
 def lookup ( key, fallback_value=None ):



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

commit:     c335d96105c50c6f988ffac378a9d17ada050874
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 14 18:50:35 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 14 18:50:35 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c335d961

config

* fix get()/_findpath()
* add key/value injection

	modified:   roverlay/config.py

---
 roverlay/config.py |   74 ++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index 3f6707b..abef63f 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -18,7 +18,7 @@ from roverlay          import const
 from roverlay.rpackage import descriptionfields
 
 
-
+CONFIG_INJECTION_IS_BAD = True
 
 def access():
 	"""Returns the ConfigTree."""
@@ -26,7 +26,7 @@ def access():
 # --- end of access (...) ---
 
 
-def get ( key, fallback_value=None ):
+def get ( key, fallback_value=None, fail_if_unset=False ):
 	"""Searches for key in the ConfigTree and returns its value if possible,
 	else fallback_value.
 	'key' is a config path [<section>[.<subsection>*]]<option name>.
@@ -36,11 +36,14 @@ def get ( key, fallback_value=None ):
 	* fallback_value --
 	"""
 	if not fallback_value is None:
-		return access().get ( key, fallback_value )
+		return access().get ( key, fallback_value, fail_if_unset )
 	else:
-		return access().get ( key )
+		return access().get ( key, fail_if_unset )
 # --- end of get (...) ---
 
+def get_or_fail ( key ):
+	return access().get ( key, fail_if_unset=True )
+# --- end of get_or_fail (...) ---
 
 class InitialLogger:
 
@@ -82,6 +85,7 @@ class ConfigTree ( object ):
 	# ** fs_path -- ~ will be expanded
 	# ** fs_dir  -- fs_path and value must be a dir if it exists
 	# ** fs_file -- fs_path and value must be a file if it exists
+	# TODO** fs_prog -- fs_file (and fs_path) and value must be executable (TODO)
 	# ** regex   -- value is a regex and will be compiled (re.compile(..))
 	#
 	#   multiple types are generally not supported ('this is an int or a str'),
@@ -115,6 +119,11 @@ class ConfigTree ( object ):
 		distfiles_dir = dict (
 			value_type = 'fs_dir',
 		),
+		ebuild_prog = dict (
+			path       = [ 'TOOLS', 'ebuild_prog' ],
+			value_type = 'fs_path',
+		),
+
 	)
 
 	# often used regexes
@@ -168,12 +177,14 @@ class ConfigTree ( object ):
 
 		config_position = self._config if root is None else root
 
+		if config_position is None: return None
+
 		for k in path:
-			if not k in config_position:
+			if k == path [-1] and not value is None:
+				# overwrite entry
+				config_position [k] = value
+			elif not k in config_position:
 				if create:
-					if k == path [-1] and not value is None:
-						config_position [k] = value
-					else:
 						config_position [k] = dict()
 				else:
 					return None
@@ -184,8 +195,32 @@ class ConfigTree ( object ):
 
 	# --- end of _findpath (...) ---
 
+	def inject ( self, key, value, suppress_log=False ):
+		"""This method offer direct write access to the ConfigTree. No checks
+		will be performed, so make sure you know what you're doing.
+
+		arguments:
+		* key -- config path of the entry to-be-created/overwritten
+		          the whole path will be created, this operation does not fail
+		          if a path component is missing ('<root>.<new>.<entry> creates
+		          root, new and entry if required)
+		* value -- value to be assigned
+
+		returns: None (implicit)
+		"""
+		if not suppress_log:
+			msg = 'config injection: value %s will '\
+				'be assigned to config key %s ...' % ( value, key )
+
+			if CONFIG_INJECTION_IS_BAD:
+				self.logger.warning ( msg )
+			else:
+				self.logger.debug ( msg )
+
+		self._findpath ( key, create=True, value=value )
+	# --- end of inject (...) ---
 
-	def get ( self, key, fallback_value=None ):
+	def get ( self, key, fallback_value=None, fail_if_unset=False ):
 		"""Searches for key in the ConfigTree and returns its value.
 		Searches in const if ConfigTree does not contain the requested key and
 		returns the fallback_value if key not found.
@@ -193,17 +228,22 @@ class ConfigTree ( object ):
 		arguments:
 		* key --
 		* fallback_value --
+		* fail_if_unset -- fail if key is neither in config nor const
 		"""
-		if self._config:
-			config_value = self._findpath ( key )
 
-			if config_value:
-				return config_value
+		config_value = self._findpath ( key )
+
+		if config_value is None:
+			fallback = None if fail_if_unset else fallback_value
+			if not self._const_imported:
+				config_value = const.lookup ( key, fallback )
+			else:
+				config_value = fallback
+
+			if config_value is None and fail_if_unset:
+				raise Exception ( "config key '%s' not found but required." % key )
 
-		if self._const_imported:
-			return fallback_value
-		else:
-			return const.lookup ( key, fallback_value )
+		return config_value
 
 	# --- end of get (...) ---
 



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

commit:     50ba18a562ef365ffbd2c7ba49a9027ba101234b
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 14 18:52:32 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 14 18:52:32 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=50ba18a5

extend roverlay.util

* added keepenv that selectively imports os.environ
* added misc functions

	modified:   roverlay/util.py

---
 roverlay/util.py |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/roverlay/util.py b/roverlay/util.py
index 5e9690d..6547906 100644
--- a/roverlay/util.py
+++ b/roverlay/util.py
@@ -6,6 +6,8 @@ import re
 import os.path
 import logging
 
+import os
+
 from roverlay import config
 
 LOGGER = logging.getLogger ( 'util' )
@@ -46,3 +48,56 @@ def get_packageinfo ( filepath ):
 	)
 
 # --- end of get_packageinfo (...) ---
+
+def get_extra_packageinfo ( package_info, name ):
+	return dict (
+		PKG_DISTDIR = os.path.dirname ( package_info ['package_file'] ),
+		EBUILD_FILE = os.path.join (
+			config.get_or_fail ( [ 'OVERLAY', 'dir' ] ),
+			config.get_or_fail ( [ 'OVERLAY', 'category' ] ),
+			package_info [ 'ebuild_filename'].partition ( '-' ) [0],
+			package_info [ 'ebuild_filename'] + ".ebuild"
+		)
+	) [name]
+# --- end of get_extra_packageinfo (...) ---
+
+def pipe_lines ( _pipe, use_filter=False, filter_func=None ):
+	lines = _pipe.decode().split ('\n')
+	if use_filter:
+		return filter ( filter_func, lines )
+	else:
+		return lines
+# --- end of pipe_lines (...) ---
+
+
+def keepenv ( *to_keep, local_env=None ):
+	if local_env is None:
+		myenv = dict()
+	else:
+		myenv = local_env
+
+	for item in to_keep:
+		if isinstance ( item, tuple ) and len ( item ) == 2:
+
+			var      = item [0]
+			fallback = item [1]
+		else:
+			var      = item
+			fallback = None
+
+		if isinstance ( var, str ):
+			if var in os.environ:
+				myenv [var] = os.environ [var]
+			elif not fallback is None:
+				myenv [var] = fallback
+		else:
+			varlist = var
+			for var in varlist:
+				if var in os.environ:
+					myenv [var] = os.environ [var]
+				elif not fallback is None:
+					myenv [var] = fallback
+
+	# -- for
+	return myenv if local_env is None else None
+# --- end of keepenv (...) ---



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

commit:     4ceeb302c882e6cb9e18c4cda2896078eff91783
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jun 12 17:13:14 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jun 12 17:13:14 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4ceeb302

roverlay

* moved get_packageinfo to util.py 'cause it'll be used for metadata creation
* misc fixes
* added value_type regex to config.py
* use depres changes, cancel ebuild creation earlier when deps are unresolved

	modified:   roverlay/__init__.py
	modified:   roverlay/config.py
	modified:   roverlay/const.py
	modified:   roverlay/descriptionreader.py
	modified:   roverlay/ebuildcreator.py
	modified:   roverlay/ebuildjob.py
	new file:   roverlay/util.py

---
 roverlay/__init__.py          |    2 +-
 roverlay/config.py            |  110 +++++++++++++++++++++++++----------------
 roverlay/const.py             |   17 +++---
 roverlay/descriptionreader.py |   63 +++--------------------
 roverlay/ebuildcreator.py     |   23 +++++----
 roverlay/ebuildjob.py         |   87 ++++++++++++++++++--------------
 roverlay/util.py              |   48 ++++++++++++++++++
 7 files changed, 196 insertions(+), 154 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index 2dab8ad..9ff69f7 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -4,7 +4,6 @@
 
 import logging
 
-
 from roverlay import config
 
 config.access().load_config ( 'R-overlay.conf' )
@@ -18,6 +17,7 @@ logging.basicConfig (
 	datefmt='%F %H:%M:%S'
 )
 
+
 # add console output to the logger
 ch = logging.StreamHandler()
 ch.setLevel ( logging.INFO )

diff --git a/roverlay/config.py b/roverlay/config.py
index 8cd99e3..6e5c433 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -82,6 +82,7 @@ class ConfigTree ( object ):
 	# ** fs_path -- ~ will be expanded
 	# ** fs_dir  -- fs_path and value must be a dir if it exists
 	# ** fs_file -- fs_path and value must be a file if it exists
+	# ** regex   -- value is a regex and will be compiled (re.compile(..))
 	#
 	#   multiple types are generally not supported ('this is an int or a str'),
 	#   but subtypes are (list of yesno), which can be specified by either
@@ -114,7 +115,6 @@ class ConfigTree ( object ):
 		distfiles_dir = dict (
 			value_type = 'fs_dir',
 		),
-
 	)
 
 	# often used regexes
@@ -123,9 +123,9 @@ class ConfigTree ( object ):
 
 
 	def __init__ ( self, import_const=True ):
-		"""Initializes an ConfigTree, which is a container for options/config values.
-		values can be stored directly (such as the field_definitions) or in a
-		tree-like { section -> subsection[s] -> option = value } structure.
+		"""Initializes an ConfigTree, which is a container for options/values.
+		Values can be stored directly (such as the field_definitions) or
+		in a tree-like { section -> subsection[s] -> option = value } structure.
 		Config keys cannot contain dots because they're used as config path
 		separator.
 
@@ -153,11 +153,13 @@ class ConfigTree ( object ):
 		value to it.
 
 		arguments:
-		* path -- config path as path list ([a,b,c]) or as path str (a.b.c)
-		* root -- config root (dict expected). Uses self._config if None (the default)
+		* path   -- config path as path list ([a,b,c]) or as path str (a.b.c)
+		* root   -- config root (dict expected).
+		             Uses self._config if None (the default)
 		* create -- create path if nonexistent
-		* value -- assign value to the last path element
-		           an empty dict will be created if this is None and create is True
+		* value  -- assign value to the last path element
+		             an empty dict will be created if this is None and
+		             create is True
 		"""
 		if path is None:
 			return root
@@ -169,7 +171,10 @@ class ConfigTree ( object ):
 		for k in path:
 			if not k in config_position:
 				if create:
-					config_position [k] = value if k == path [-1] and value else dict ()
+					if k == path [-1] and not value is None:
+						config_position [k] = value
+					else:
+						config_position [k] = dict()
 				else:
 					return None
 
@@ -206,8 +211,8 @@ class ConfigTree ( object ):
 		"""Adds an option to the config.
 
 		arguments:
-		* option -- name of the option as it appears in the (main) config file
-		* value -- value to assign, defaults to None
+		* option      -- name of the option as it appears in the config file
+		* value       -- value to assign, defaults to None
 		* config_root -- root of the config (a dict), defaults to None which is
 		                 later understood as self._config
 		"""
@@ -217,8 +222,9 @@ class ConfigTree ( object ):
 			in the ConfigTree.
 
 			arguments:
-			* value_type -- type of the value, look above for explanation concerning this
-			* value -- value to verify and transform
+			* value_type      -- type of the value,
+			                      look above for explanation concerning this
+			* value           -- value to verify and transform
 			* entryconfig_ref -- reference to the config entry config
 			"""
 
@@ -269,8 +275,8 @@ class ConfigTree ( object ):
 			# --- end of fs_path (...) ---
 
 			def fs_file ( val ):
-				""""val is a file - returns expanded path if it is an existent
-				file or it does not exist.
+				""""val is a file - returns expanded path if it is
+				an existent file or it does not exist.
 
 				arguments:
 				* val --
@@ -284,8 +290,8 @@ class ConfigTree ( object ):
 			# --- end of fs_file (...) ---
 
 			def fs_dir ( val ):
-				"""val is a directory -- returns expanded path if it is an existent
-				dir or it does not exist.
+				"""val is a directory -- returns expanded path if it is
+				an existent dir or it does not exist.
 
 				arguments:
 				* val --
@@ -298,6 +304,15 @@ class ConfigTree ( object ):
 				return None
 			# --- end of fs_dir (...) ---
 
+			def _regex ( val ):
+				"""val is a regex -- compile it if possible
+
+				arguments:
+				* val --
+				"""
+				return re.compile ( val ) if not val is None else None
+			# --- end of _regex (...) ---
+
 			# replace whitespace with a single ' '
 			value = ConfigTree.WHITESPACE.sub ( ' ', value )
 
@@ -320,10 +335,12 @@ class ConfigTree ( object ):
 				'int'     : to_int,
 				'fs_path' : fs_path,
 				'fs_file' : fs_file,
+				'regex'   : _regex,
 			}
 
 			# dofunc ( function f, <list or str> v) calls f(x) for every str in v
-			dofunc = lambda f, v : [ f(x) for x in v ] if isinstance ( v, list ) else f(v)
+			dofunc = lambda f, v : [ f(x) for x in v ] \
+				if isinstance ( v, list ) else f(v)
 
 			retval = value
 
@@ -349,7 +366,9 @@ class ConfigTree ( object ):
 			# check if cref is a link to another entry in CONFIG_ENTRY_MAP
 			while isinstance ( cref, str ) and cref != '':
 				if cref == original_cref and cref_level:
-					self.logger.critical ( "CONFIG_ENTRY_MAP is invalid! circular cref detected." )
+					self.logger.critical (
+						"CONFIG_ENTRY_MAP is invalid! circular cref detected."
+					)
 					raise Exception ( "CONFIG_ENTRY_MAP is invalid!" )
 
 				elif cref in ConfigTree.CONFIG_ENTRY_MAP:
@@ -357,10 +376,9 @@ class ConfigTree ( object ):
 					cref = ConfigTree.CONFIG_ENTRY_MAP [cref]
 					cref_level += 1
 				else:
-					# TODO %s
 					self.logger.critical (
-						"CONFIG_ENTRY_MAP is invalid! last cref = " + option +
-						", current cref = " + cref + "."
+						'CONFIG_ENTRY_MAP is invalid! '
+						'last cref = %s, current cref = %s.' % ( option, cref )
 					)
 					raise Exception ( "CONFIG_ENTRY_MAP is invalid!" )
 
@@ -384,15 +402,16 @@ class ConfigTree ( object ):
 
 				# verify and convert value if value_type is set
 				if 'value_type' in cref:
-					value = make_and_verify_value ( cref ['value_type'], value, cref )
+					value = make_and_verify_value (
+						cref ['value_type'], value, cref
+					)
 
 				# need a valid value
 				if value:
 
 					self.logger.debug (
-						"New config entry " + str ( option ) +
-						" with path " + str ( path ) +
-						" and value " + str ( value ) + "."
+						"New config entry %s with path %s and value %s." %
+							( option, path, value )
 					)
 
 					# add option/value to the config
@@ -401,17 +420,17 @@ class ConfigTree ( object ):
 					return True
 				else:
 					self.logger.error (
-						"Option '" + str ( real_option ) +
-						"' has an unusable value '" + str ( value ) + "'."
+						"Option '%s' has an unusable value '%s'." %
+							( real_option, value )
 					)
 					return False
 			# ---
 
-			self.logger.error ( "Option '" + str ( real_option ) + "' is unusable..." )
+			self.logger.error ( "Option '%s' is unusable..." % real_option )
 			return False
 		# ---
 
-		self.logger.warning ( "Option '" + str ( real_option ) + "' is unknown." )
+		self.logger.warning ( "Option '%s' is unknown." % real_option )
 		return False
 
 	# --- end of _add_entry (...) ---
@@ -450,9 +469,10 @@ class ConfigTree ( object ):
 				if equal == '=':
 					self._add_entry ( option, value, config_root )
 				else:
+
 					self.logger.warning (
-						"In '" + config_file + "', cannot parse this line: '" +
-						str ( option ) + str ( equal ) + str ( value ) + "'."
+						"In '%s', cannot parse this line: '%s%s%s'." %
+							( config_file, option, equal, value )
 					)
 
 				option, equal, value = nextline ()
@@ -466,25 +486,30 @@ class ConfigTree ( object ):
 	# --- end of load_config (...) ---
 
 	def load_field_definition ( self, def_file, lenient=False ):
-		"""Loads a field definition file. Please see the example file for format
-		details.
+		"""Loads a field definition file.
+		Please see the example file for format details.
 
 		arguments:
-		* def_file -- file (str) to read, this can be a list of str if lenient is True
-		* lenient  -- if True: do not fail if a file cannot be read; defaults to False
+		* def_file -- file (str) to read,
+		               this can be a list of str if lenient is True
+		* lenient  -- if True: do not fail if a file cannot be read;
+		               defaults to False
 		"""
 		if not 'field_def' in self.parser:
-			self.parser ['field_def'] = configparser.SafeConfigParser ( allow_no_value=True )
+			self.parser ['field_def'] = \
+				configparser.SafeConfigParser ( allow_no_value=True )
 
 		try:
-			self.logger.debug ( "Reading description field definition file " + def_file + "." )
+			self.logger.debug (
+				"Reading description field definition file %s." % def_file
+			)
 			if lenient:
 				self.parser ['field_def'] . read ( def_file )
 			else:
 				fh = open ( def_file, 'r' )
 				self.parser ['field_def'] . readfp ( fh )
-				if fh:
-					fh.close()
+
+				if fh: fh.close()
 		except IOError as err:
 			self.logger.exception ( err )
 			raise
@@ -521,14 +546,13 @@ class ConfigTree ( object ):
 				l = value_str.split ( ', ' )
 				return [ e for e in l if e.strip() ]
 
-		if not 'field_def' in self.parser:
-			return None
+		if not 'field_def' in self.parser: return None
 
 		fdef = descriptionfields.DescriptionFields ()
 
 		for field_name in self.parser ['field_def'].sections():
 			field = descriptionfields.DescriptionField ( field_name )
-			for option, value in self.parser ['field_def'].items ( field_name, 1 ):
+			for option, value in self.parser ['field_def'].items( field_name, 1 ):
 
 				if option == 'alias' or option == 'alias_withcase':
 					for alias in get_list ( value ):

diff --git a/roverlay/const.py b/roverlay/const.py
index 32a7e89..7ab1891 100644
--- a/roverlay/const.py
+++ b/roverlay/const.py
@@ -18,14 +18,15 @@ _CONSTANTS = dict (
 	),
 	EBUILD = dict (
 		indent         = '\t',
-		default_header = [	'# Copyright 1999-' + str ( time.gmtime() [0] ) + ' Gentoo Foundation',
-									'# Distributed under the terms of the GNU General Public License v2',
-									'# $Header: $',
-									'',
-									'EAPI=4',
-									'',
-									'inherit R-packages'
-								],
+		default_header = [
+			'# Copyright 1999-%i Gentoo Foundation' % ( time.gmtime() [0] ),
+			'# Distributed under the terms of the GNU General Public License v2',
+			'# $Header: $',
+			'',
+			'EAPI=4',
+			'',
+			'inherit R-packages'
+		],
 	)
 )
 

diff --git a/roverlay/descriptionreader.py b/roverlay/descriptionreader.py
index ad70239..01eb92a 100644
--- a/roverlay/descriptionreader.py
+++ b/roverlay/descriptionreader.py
@@ -13,18 +13,20 @@ from roverlay import descriptionfields
 class DescriptionReader ( object ):
 	"""Description Reader"""
 
-	LOGGER = logging.getLogger ( 'DescriptionReader' )
+	#LOGGER = logging.getLogger ( 'DescriptionReader' )
 
 
-	def __init__ ( self, package_file, read_now=False ):
+	def __init__ ( self, package_info, logger, read_now=False ):
 		"""Initializes a DESCRIPTION file reader."""
 
 		if not config.access().get_field_definition():
-			raise Exception ( "Field definition is missing, cannot initialize DescriptionReader." )
+			raise Exception (
+				"Field definition is missing, cannot initialize DescriptionReader."
+			)
 
 		self.field_definition = config.access().get_field_definition()
-		self.fileinfo         = self.make_fileinfo ( package_file )
-		self.logger           = DescriptionReader.LOGGER.getChild ( self.get_log_name() )
+		self.fileinfo         = package_info
+		self.logger           = logger.getChild ( 'desc_reader' )
 		self.desc_data        = None
 
 
@@ -33,15 +35,6 @@ class DescriptionReader ( object ):
 
 	# --- end of __init__ (...) ---
 
-	def get_log_name ( self ):
-		"""Returns a logging name that can be used in other modules."""
-		try:
-			return self.fileinfo ['filename']
-		except Exception as any_exception:
-			return '__undef__'
-	# --- end of get_log_name (...) ---
-
-
 	def get_desc ( self, run_if_unset=True ):
 		if self.desc_data is None:
 			self.run ()
@@ -49,43 +42,6 @@ class DescriptionReader ( object ):
 		return self.desc_data
 	# --- end of get_desc (...) ---
 
-	def get_fileinfo ( self ):
-		return self.fileinfo
-	# --- end of get_fileinfo (...) ---
-
-	def make_fileinfo ( self, filepath ):
-		"""Returns some info about the given filepath as dict whose contents are
-			the file path, the file name ([as package_file with suffix and]
-			as filename with tarball suffix removed), the package name
-			and the package_version.
-
-		arguments:
-		* filepath --
-		"""
-
-		package_file = os.path.basename ( filepath )
-
-		filename = re.sub ( config.get ( 'R_PACKAGE.suffix_regex' ) + '$', '', package_file )
-
-		package_name, sepa, package_version = filename.partition (
-			config.get ( 'R_PACKAGE.name_ver_separator', '_' )
-		)
-
-		if not sepa:
-			# file name unexpected, tarball extraction will (probably) fail
-			DescriptionReader.LOGGER.error ( "unexpected file name %s.'", filename )
-
-		return dict (
-			filepath        = filepath,
-			filename        = filename,
-			package_file    = package_file,
-			package_name    = package_name,
-			#package_origin = ?,
-			package_version = package_version,
-		)
-
-	# --- end of make_fileinfo (...) ---
-
 	def _parse_read_data ( self, read_data ):
 		"""Verifies and parses/fixes read data.
 
@@ -93,7 +49,6 @@ class DescriptionReader ( object ):
 		* read_data -- data from file, will be modified
 		"""
 
-
 		# insert default values
 		default_values = self.field_definition.get_fields_with_default_value()
 		for field_name in default_values.keys():
@@ -153,8 +108,8 @@ class DescriptionReader ( object ):
 		-> split field values
 		-> filter out unwanted/useless fields
 
-		The return value is a dict { fileinfo , description_data } or None if
-		the read data are "useless" (not suited to create an ebuild for it,
+		The return value is a description_data dict or None if the read data
+		are "useless" (not suited to create an ebuild for it,
 		e.g. if OS_TYPE is not unix).
 		"""
 

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index 4ece851..6daf471 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -2,8 +2,8 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import threading
 import logging
+import threading
 
 try:
 	import queue
@@ -11,6 +11,7 @@ except ImportError:
 	# python2
 	import Queue as queue
 
+
 from roverlay                 import config
 from roverlay.ebuildjob       import EbuildJob
 from roverlay.depres          import depresolver
@@ -34,7 +35,7 @@ class EbuildCreator ( object ):
 		self.runlock  = threading.Lock()
 		self._threads = None
 
-		self.logger   = logging.getLogger ( 'EbuildCreator' )
+		self.logger = logging.getLogger ( 'EbuildCreator' )
 
 	# --- end of init (...) ---
 
@@ -46,7 +47,6 @@ class EbuildCreator ( object ):
 		arguments:
 		* package_file -- path R package file
 		"""
-
 		new_job = EbuildJob ( package_file, self.get_resolver_channel )
 
 		self.ebuild_jobs.put ( new_job )
@@ -55,14 +55,16 @@ class EbuildCreator ( object ):
 
 	# --- end of add_package (...) ---
 
-	def get_resolver_channel ( self, name=None ):
+	def get_resolver_channel ( self, name=None, logger=None ):
 		"""Returns a communication channel to the dependency resolver.
 
 		arguments:
 		readonly -- whether the channel is listen-only (no write methods) or not
 		            defaults to True
 		"""
-		return self.depresolve_main.register_channel ( EbuildJobChannel ( name=name ) )
+		return self.depresolve_main.register_channel (
+			EbuildJobChannel ( name=name, logger=logger )
+		)
 
 	# --- end of get_resolver_channel (...) ---
 
@@ -84,7 +86,7 @@ class EbuildCreator ( object ):
 
 	# --- end of _thread_run (...) ---
 
-	def run ( self ):
+	def start ( self ):
 		"""Tells all EbuildJobs to run."""
 
 		if not self.runlock.acquire ( False ):
@@ -95,10 +97,9 @@ class EbuildCreator ( object ):
 		jobcount = EbuildCreator.NUMTHREADS
 
 		if jobcount < 1:
-			if jobcount < 0:
-				self.logger.warning ( "Running in sequential mode." )
-			else:
-				self.logger.debug ( "Running in sequential mode." )
+			( self.logger.warning if jobcount < 0 else self.logger.debug ) (
+				"Running in sequential mode."
+			)
 			self._thread_run()
 		else:
 			self.logger.warning (
@@ -118,7 +119,7 @@ class EbuildCreator ( object ):
 
 		self.runlock.release()
 
-	# --- end of run (...) ---
+	# --- end of start (...) ---
 
 	def collect_ebuilds ( self ):
 		"""Returns all ebuilds. (They may not be ready / TODO)"""

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index ccd2f2a..8b13e67 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -5,9 +5,11 @@
 import logging
 import re
 
+from roverlay                   import config, util
+from roverlay.ebuild            import Ebuild
 from roverlay.descriptionreader import DescriptionReader
-from roverlay.ebuild import Ebuild
-from roverlay import config
+
+
 
 class EbuildJob ( object ):
 	LOGGER = logging.getLogger ( 'EbuildJob' )
@@ -37,7 +39,7 @@ class EbuildJob ( object ):
 		"""Initializes an EbuildJob, which creates an ebuild for an R package.
 
 		arguments:
-		* package_file -- path to the R package file
+		* package_info -- R package file info
 		* dep_resolver -- dependency resolver
 		"""
 
@@ -46,10 +48,18 @@ class EbuildJob ( object ):
 		dep resolver 'communication channel', status codes etc.
 		"""
 
-		# get description reader from args?
-		self.description_reader = DescriptionReader ( package_file )
+		self.package_info = util.get_packageinfo ( package_file )
+
+		try:
+			self.logger = EbuildJob.LOGGER.getChild (
+				self.package_info ['filename']
+			)
+		except KeyError:
+			self.logger = EbuildJob.LOGGER.getChild ( '__undef__' )
 
-		self.logger = EbuildJob.LOGGER.getChild ( self.description_reader.get_log_name () )
+		self.description_reader = DescriptionReader (
+			self.package_info, logger=self.logger
+		)
 
 		self.ebuild = None
 
@@ -67,17 +77,19 @@ class EbuildJob ( object ):
 	# --- end of __init__ (...) ---
 
 	def get_resolver ( self, dependency_type ):
+		# comment TODO
 		if not dependency_type in self._depres:
-			self._depres [dependency_type] = self.request_resolver ( dependency_type )
+			self._depres [dependency_type] = \
+				self.request_resolver ( dependency_type, self.logger )
 
 		return self._depres [dependency_type]
-
+	# --- end of get_resolver (...) ---
 
 	def get_ebuild ( self ):
 		"""Returns the Ebuild that is created by this object. Note that you should
 		check the status with status ( $TODO::EBUILD_READY ) before trying to use
 		the Ebuild.
-		##fixme: it is guaranteed that self.ebuild is None unless the Ebuild is successfully created##
+		##fixme: it is (should be?) guaranteed that self.ebuild is None unless the Ebuild is successfully created##
 		"""
 		return self.ebuild
 
@@ -103,7 +115,6 @@ class EbuildJob ( object ):
 
 	# --- end of done_success (...) ---
 
-
 	def run ( self ):
 		"""Tells this EbuildJob to run. This means that it reads the package file,
 		resolves dependencies using its resolver (TODO) and creates
@@ -124,7 +135,7 @@ class EbuildJob ( object ):
 				self.logger.info ( 'Cannot create an ebuild for this package.' )
 
 
-			fileinfo  = self.description_reader.get_fileinfo ()
+			fileinfo  = self.package_info
 
 			ebuild = Ebuild ( self.logger.getChild ( "Ebuild" ) )
 
@@ -180,35 +191,43 @@ class EbuildJob ( object ):
 							else:
 								resolver.add_depency ( desc [desc_field] )
 
-					del resolver
 
+				# lazy depres: wait until done and stop if any resolver channel
+				# returns None (which implies failure)
+				# wait for depres and store results
+				resolved = True
 
-				resolver_list = self._depres.values()
-
-				# trigger depres...
-				for r in resolver_list: r.trigger_run()
-
-				# and wait
 				if not self._set_status ( 'WAIT_RESOLVE' ): return
-				for r in resolver_list: r.join()
+
+				for resolver in self._depres.values():
+					if resolver.satisfy_request() is None:
+						resolved = False
+						break
 
 				if not self._set_status ( 'BUSY' ): return
 
-				# check if all deps resolved, which means that all channels have
-				# to return True
-				if not False in ( r.satisfy_request() for r in resolver_list ):
+				if not resolved:
+					# ebuild is not creatable, set status to FAIL and close dep resolvers
+					self.logger.info (
+						"Failed to resolve dependencies for this package."
+					)
+					for r in self._depres.values(): r.close ()
+					self._set_status ( 'FAIL' )
+					return
+				else:
 					# add deps to the ebuild
 					for dep_type, resolver in self._depres.items():
-
 						# python3 requires list ( filter ( ... ) )
-						deplist = list ( filter ( None, resolver.collect_dependencies () ) )
+						deplist = list (
+							filter ( None, resolver.collect_dependencies () )
+						)
 
 						if deplist is None:
-							## false positive: "empty" channel
-							raise Exception (
-								'dep_resolver is broken: '
-								'lookup() returns None but satisfy_request() says ok.'
-							)
+							## FIXME: false positive: "empty" channel
+								raise Exception (
+									'dep_resolver is broken: '
+									'lookup() returns None but satisfy_request() says ok.'
+								)
 						elif isinstance ( deplist, ( list, set ) ):
 							# add dependencies in no_append/override mode
 							self.logger.debug ( "adding %s to %s", str (deplist), dep_type )
@@ -220,15 +239,9 @@ class EbuildJob ( object ):
 							)
 					# --- end for
 
-					# tell the dep resolver channels that we're done
-					for r in resolver_list: r.close ()
 
-				else:
-					# ebuild is not creatable, set status to FAIL and close dep resolvers
-					self.logger.info ( "Failed to resolve dependencies for this package." )
-					for r in resolver_list: r.close ()
-					self._set_status ( 'FAIL' )
-					return
+					# tell the dep resolver channels that we're done
+					for r in self._depres.values(): r.close ()
 
 			# --- end dep resolution
 

diff --git a/roverlay/util.py b/roverlay/util.py
new file mode 100644
index 0000000..5e9690d
--- /dev/null
+++ b/roverlay/util.py
@@ -0,0 +1,48 @@
+# R Overlay -- helper functions etc.
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import re
+import os.path
+import logging
+
+from roverlay import config
+
+LOGGER = logging.getLogger ( 'util' )
+
+
+def get_packageinfo ( filepath ):
+	"""Returns some info about the given filepath as dict whose contents are
+		the file path, the file name ([as package_file with suffix and]
+		as filename with tarball suffix removed), the package name
+		and the package_version.
+
+	arguments:
+	* filepath --
+	"""
+
+	package_file = os.path.basename ( filepath )
+
+	# remove .tar.gz .tar.bz2 etc.
+	filename = re.sub (
+		config.get ( 'R_PACKAGE.suffix_regex' ) + '$', '', package_file
+	)
+
+	package_name, sepa, package_version = filename.partition (
+		config.get ( 'R_PACKAGE.name_ver_separator', '_' )
+	)
+
+	if not sepa:
+		# file name unexpected, tarball extraction will (probably) fail
+		LOGGER.error ( "unexpected file name '%s'." % filename )
+
+	return dict (
+		filepath        = filepath,
+		filename        = filename,
+		package_file    = package_file,
+		package_name    = package_name,
+		#package_origin = ?,
+		package_version = package_version,
+	)
+
+# --- end of get_packageinfo (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-06 19:52 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-06 19:52 UTC (permalink / raw
  To: gentoo-commits

commit:     1f51ac4acac24633cba9d7a531c7165af7acd09d
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun  6 19:47:58 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun  6 19:47:58 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1f51ac4a

descriptionfields.py: reduce function calls
	modified:   roverlay/descriptionfields.py

---
 roverlay/descriptionfields.py |   60 +++++++++++++++++------------------------
 1 files changed, 25 insertions(+), 35 deletions(-)

diff --git a/roverlay/descriptionfields.py b/roverlay/descriptionfields.py
index 72175cb..710f0c0 100644
--- a/roverlay/descriptionfields.py
+++ b/roverlay/descriptionfields.py
@@ -19,6 +19,11 @@ class DescriptionField:
 
 		self.name = name
 
+		self.default_value  = None
+		self.flags          = list ()
+		self.allowed_values = list ()
+		self.aliases        = dict ()
+
 	# --- end of __init__ (...) ---
 
 
@@ -36,10 +41,7 @@ class DescriptionField:
 		arguments:
 		* flag -- name of the flag
 		"""
-		if not hasattr ( self, 'flags' ):
-			self.flags = set ()
-
-		self.flags.add ( flag.lower() )
+		self.flags.append ( flag.lower() )
 
 		return None
 
@@ -55,10 +57,7 @@ class DescriptionField:
 		* value -- allowed value
 		"""
 
-		if not hasattr ( self, 'allowed_values' ):
-			self.allowed_values = set ()
-
-		self.allowed_values.add ( value )
+		self.allowed_values.append ( value )
 
 		return None
 
@@ -69,8 +68,7 @@ class DescriptionField:
 		"""Removes a flag from this DescriptionField. Does nothing if the flag
 		does not exist.
 		"""
-		if hasattr ( self, 'flags' ):
-			self.flags.discard ( flag.lower() )
+		self.flags.discard ( flag.lower() )
 		return None
 
 	# --- end of del_flag (...) ---
@@ -90,8 +88,6 @@ class DescriptionField:
 
 		raises: KeyError if alias_type unknown.
 		"""
-		if not hasattr ( self, 'aliases' ):
-			self.aliases = dict ()
 
 		to_add = dict (
 			withcase = alias,
@@ -100,9 +96,9 @@ class DescriptionField:
 
 
 		if not alias_type in self.aliases:
-			self.aliases [alias_type] = set ()
+			self.aliases [alias_type] = list ()
 
-		self.aliases [alias_type] . add ( to_add )
+		self.aliases [alias_type] . append ( to_add )
 
 		return None
 
@@ -128,7 +124,7 @@ class DescriptionField:
 		"""Returns the default value for this DescriptionField if it exists,
 		else None.
 		"""
-		return self.default_value if hasattr ( self, 'default_value' ) else None
+		return self.default_value
 
 	# --- end of get_default_value (...) ---
 
@@ -146,7 +142,7 @@ class DescriptionField:
 
 	def get_flags ( self ):
 		"""Returns the flags of this DescriptionField or an empty list (=no flags)."""
-		return self.flags if hasattr ( self, 'flags' ) else []
+		return self.flags
 
 	# --- end of get_flags (...) ---
 
@@ -155,7 +151,7 @@ class DescriptionField:
 		"""Returns the allowed values of this DescriptionField or an empty list,
 		which should be interpreted as 'no value restriction'.
 		"""
-		return self.allowed_values if hasattr ( self, 'allowed_values' ) else []
+		return self.allowed_values
 
 	# --- end of get_allowed_values (...) ---
 
@@ -181,9 +177,6 @@ class DescriptionField:
 		if not field_identifier:
 			# bad identifier
 			return False
-		elif not hasattr ( self, aliases ):
-			# no aliases
-			return False
 
 		if 'withcase' in self.aliases:
 			if field_identifier in self.aliases ['withcase']:
@@ -194,6 +187,8 @@ class DescriptionField:
 			if field_id_lower in self.aliases ['nocase']:
 				return True
 
+		return False
+
 	# --- end of matches_alias (...) ---
 
 
@@ -203,9 +198,6 @@ class DescriptionField:
 		arguments:
 		* flag --
 		"""
-		if not hasattr ( self, 'flags' ):
-			return False
-
 		return bool ( flag.lower() in self.flags )
 
 	def value_allowed ( self, value, nocase=True ):
@@ -215,18 +207,17 @@ class DescriptionField:
 		* value -- value to check
 		* nocase -- if True (the default): be case insensitive
 		"""
-		allowed_values = self.get_allowed_values ()
 
-		if not allowed_values:
+		if not self.allowed_values:
 			return True
 		elif nocase:
 			lowval = value.lower()
-			for allowed in allowed_values:
+			for allowed in self.allowed_values:
 				if allowed.lower() == lowval:
 					return True
 
 		else:
-			return bool ( value in allowed_values )
+			return bool ( value in self.allowed_values )
 
 		return False
 
@@ -315,22 +306,21 @@ class DescriptionFields:
 		flagmap   = dict ()
 		optionmap = dict (
 			defaults       = dict (),
-			allowed_values = set ()
+			allowed_values = list ()
 		)
 
 		for field_name in self.fields.keys():
-
-			d = self.fields [field_name].get_default_value()
+			d = self.fields [field_name].default_value
 			if not d is None:
 				optionmap ['defaults'] [field_name] = d
 
-			if self.fields [field_name].get_allowed_values():
-				optionmap ['allowed_values'].add ( field_name )
+			if self.fields [field_name].allowed_values:
+				optionmap ['allowed_values'].append ( field_name )
 
-			for flag in self.fields [field_name].get_flags():
+			for flag in self.fields [field_name].flags:
 				if not flag in flagmap:
-					flagmap [flag] = set ()
-				flagmap [flag].add ( field_name )
+					flagmap [flag] = list ()
+				flagmap [flag].append ( field_name )
 
 		self._fields_by_flag   = flagmap
 		self._fields_by_option = optionmap



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-06 19:52 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-06 19:52 UTC (permalink / raw
  To: gentoo-commits

commit:     f0a5ee703f0d23a4968963f57817336486806451
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun  6 19:47:12 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun  6 19:47:12 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f0a5ee70

add dependency resolution to ebuild creation

	modified:   roverlay/ebuildcreator.py
	modified:   roverlay/ebuildjob.py

---
 roverlay/ebuildcreator.py |   11 +++--
 roverlay/ebuildjob.py     |  111 ++++++++++++++++++++++++++++-----------------
 2 files changed, 75 insertions(+), 47 deletions(-)

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index bc74490..3713c3b 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -3,6 +3,8 @@
 # Distributed under the terms of the GNU General Public License v2
 
 from roverlay.ebuildjob import EbuildJob
+from roverlay.depres import depresolver
+from roverlay.depres.communication import EbuildJobChannel
 
 class EbuildCreator:
 
@@ -12,7 +14,7 @@ class EbuildCreator:
 		every R package added.
 		"""
 		self.ebuild_headers = dict ()
-		self.depresolve_main = None # TODO
+		self.depresolve_main = depresolver.DependencyResolver ()
 		self.ebuild_jobs = []
 
 	# --- end of init (...) ---
@@ -26,7 +28,7 @@ class EbuildCreator:
 		* package_file -- path R package file
 		"""
 
-		new_job = EbuildJob ( package_file, self.get_resolver ( False ) )
+		new_job = EbuildJob ( package_file, self.get_resolver_channel )
 
 		self.ebuild_jobs.append ( new_job )
 
@@ -34,15 +36,14 @@ class EbuildCreator:
 
 	# --- end of add_package (...) ---
 
-	def get_resolver ( self, readonly=True ):
+	def get_resolver_channel ( self, name=None ):
 		"""Returns a communication channel to the dependency resolver.
 
 		arguments:
 		readonly -- whether the channel is listen-only (no write methods) or not
 		            defaults to True
 		"""
-		# <TODO>
-		return None
+		return self.depresolve_main.register_channel ( EbuildJobChannel ( name=name ) )
 		#return self.depresolve_main.get_channel()
 
 	# --- end of get_resolver (...) ---

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index be8e5e3..fa13a48 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -36,7 +36,7 @@ class EbuildJob:
 		FAIL         = [],
 	)
 
-	def __init__ ( self, package_file, dep_resolver=None ):
+	def __init__ ( self, package_file, depres_channel_spawner=None ):
 		"""Initializes an EbuildJob, which creates an ebuild for an R package.
 
 		arguments:
@@ -49,8 +49,6 @@ class EbuildJob:
 		dep resolver 'communication channel', status codes etc.
 		"""
 
-		#self.package_file = package_file
-		self.dep_resolver = dep_resolver
 		# get description reader from args?
 		self.description_reader = DescriptionReader ( package_file )
 
@@ -58,10 +56,26 @@ class EbuildJob:
 
 		self.ebuild = None
 
+		# only allow a function (at least callable) for self.get_resolver
+		if hasattr ( depres_channel_spawner, '__call__' ):
+			self.request_resolver = depres_channel_spawner
+			# _depres contains (almost) dependency resolution data/.., including
+			# communication channels and should only be modified in run()
+			self._depres = dict ()
+		else:
+			self.request_resolver = None
+
 		self.status = 'INIT'
 
 	# --- end of __init__ (...) ---
 
+	def get_resolver ( self, dependency_type ):
+		if not dependency_type in self._depres:
+			self._depres [dependency_type] = self.request_resolver ()
+
+		return self._depres [dependency_type]
+
+
 	def get_ebuild ( self ):
 		"""Returns the Ebuild that is created by this object. Note that you should
 		check the status with status ( $TODO::EBUILD_READY ) before trying to use
@@ -148,73 +162,86 @@ class EbuildJob:
 								False
 							)
 
-			if self.dep_resolver and self.dep_resolver.enabled():
+			if not self.request_resolver is None:
+
+				dep_type = desc_field = None
 
-				# collect depdencies from desc and add them to the resolver
-				raw_depends = dict ()
 
-				dep_type = field = None
+				for dep_type in EbuildJob.DEPENDENCY_FIELDS:
 
-				for dep_type in EbuildJob.DEPENDENCY_FIELDS.keys():
+					resolver = None
 
-					raw_depends [dep_type] = []
+					for desc_field in EbuildJob.DEPENDENCY_FIELDS [dep_type]:
 
-					for field in EbuildJob.DEPENDENCY_FIELDS [dep_type]:
+						if desc_field in desc:
+							if not resolver:
+								resolver = self.get_resolver ( dep_type )
 
-						if field in desc:
-							if isinstance ( desc [field], list ):
-								raw_depends.extend ( desc [field] )
-								self.dep_resolver.add_dependencies ( desc [field] )
+							if isinstance ( desc [desc_field], list ):
+								resolver.add_dependencies ( desc [desc_field] )
 
 							else:
-								raw_depends.append ( desc [field] )
-								self.dep_resolver.add_depency ( desc [field] )
+								resolver.add_depency ( desc [desc_field] )
 
-				del field, dep_type
+					del resolver
 
 
-				while not self.dep_resolver.done():
+				# wait
+				resolver_list = self._depres.values()
+				wait_resolve = True
+				while wait_resolve:
+					wait_resolve = False
 
 					if not self._set_status ( 'WAIT_RESOLVE' ): return
 
+					self.logger.debug ( "WAITING" )
+
 					# tell the resolver to run (again)
-					self.dep_resolver.run()
+					for r in resolver_list : r.trigger_run ()
 
 					if not self._set_status ( 'BUSY' ): return
 
-				if self.dep_resolver.satisfy_request():
+					for r in resolver_list :
+						if not r.done ():
+							wait_resolve = True
+							break
 
-					dep_type = dep_str = dep = None
 
+				# check if all deps resolved
+				deps_resolved = True
+				for r in resolver_list:
+					if not r.satisfy_request():
+						deps_resolved = False
+						break
+
+				if deps_resolved:
 					# dependencies resolved, add them to the ebuild
-					for dep_type in raw_depends.keys():
-
-						for dep_str in raw_depends [dep_type]:
-							# lookup (str) should return a str here
-							dep = self.dep_resolver.lookup ( dep_str )
-							if dep is None:
-								raise Exception (
-									"dep_resolver is broken: lookup() returns None but satisfy_request() says ok."
-								)
-							else:
-								# add depencies in append mode
-								dep = self.dep_resolver.lookup ( dep_str )
-								ebuild.add ( dep_type,
-													self.dep_resolver.lookup ( dep_str ),
-													True
-												)
+					for dep_type, resolver in self._depres.items():
+
+						deplist = resolver.collect_dependencies ()
 
-					del dep, dep_str, dep_type
+						if deplist is None or not isinstance ( deplist, list ):
+							## false positive: "empty" channel
+							raise Exception (
+								"dep_resolver is broken: lookup() returns None but satisfy_request() says ok."
+							)
+						else:
+							# add dependencies in no_append/override mode
+							ebuild.add ( dep_type, deplist, False )
 
-					# tell the dep resolver that we're done here
-					self.dep_resolver.close()
+							# tell the dep resolver channels that we're done
+							for r in resolver_list: r.close ()
 
 				else:
-					# ebuild is not creatable, set status to FAIL and close dep resolver
+					# ebuild is not creatable, set status to FAIL and close dep resolvers
+					self.logger.info ( "Failed to resolve dependencies for this package." )
+					for r in resolver_list: r.close ()
 					self._set_status ( 'FAIL' )
-					self.dep_resolver.close()
 					return
 
+			# --- end dep resolution
+
+
 			## finalize self.ebuild: forced text creation + make it readonly
 			if ebuild.prepare ( True, True ):
 				self.ebuild = ebuild



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-06 19:52 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-06 19:52 UTC (permalink / raw
  To: gentoo-commits

commit:     30dd2c76ba89169931784493cf326dd691a4a7bc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jun  6 19:43:22 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jun  6 19:43:22 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=30dd2c76

roverlay/config.py: fix _add_entry(...)

---
 roverlay/config.py |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index 424e69f..6753d4e 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -328,7 +328,7 @@ class ConfigTree:
 			cref_level = 0
 
 			# check if cref is a link to another entry in CONFIG_ENTRY_MAP
-			while isinstance ( cref, str ):
+			while isinstance ( cref, str ) and cref != '':
 				if cref == original_cref and cref_level:
 					self.logger.critical ( "CONFIG_ENTRY_MAP is invalid! circular cref detected." )
 					raise Exception ( "CONFIG_ENTRY_MAP is invalid!" )
@@ -415,12 +415,13 @@ class ConfigTree:
 		# load file
 
 		try:
+			fh     = open ( config_file, 'r' )
+			reader = shlex.shlex ( fh )
 			reader.wordchars       += ' ./$()[]:+-@*~'
-			fh                      = open ( config_file, 'r' )
-			reader                  = shlex.shlex ( fh )
 			reader.whitespace_split = False
 
 
+
 			nextline = lambda : ( reader.get_token() for n in range (3) )
 
 			option, equal, value = nextline ()



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-05 17:30 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-05 17:30 UTC (permalink / raw
  To: gentoo-commits

commit:     85bca473d98e6c1e9217b299d54fa3499b407e3c
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jun  5 17:18:34 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jun  5 17:18:34 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=85bca473

config: comments and config entry map
	modified:   roverlay/config.py

---
 roverlay/config.py |  133 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 116 insertions(+), 17 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index ab6dfec..424e69f 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -2,7 +2,6 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import copy
 import os.path
 import re
 import sys
@@ -89,13 +88,21 @@ class ConfigTree:
 		),
 		ebuild_header = dict (
 			value_type = 'fs_file',
-		)
+		),
+		overlay_dir   = dict (
+			value_type = 'fs_dir',
+		),
+		distfiles_dir = dict (
+			value_type = 'fs_dir',
+		),
 
 	)
 
+	# often used regexes
 	DEFAULT_LIST_REGEX = re.compile ( '\s*[,;]{1}\s*' )
 	WHITESPACE         = re.compile ( '\s+' )
 
+
 	def __init__ ( self, import_const=True ):
 		"""Initializes an ConfigTree, which is a container for options/config values.
 		values can be stored directly (such as the field_definitions) or in a
@@ -122,6 +129,17 @@ class ConfigTree:
 
 
 	def _findpath ( self, path, root=None, create=False, value=None ):
+		"""All-in-one method that searches for a config path.
+		It is able to create the path if non-existent and to assign a
+		value to it.
+
+		arguments:
+		* path -- config path as path list ([a,b,c]) or as path str (a.b.c)
+		* root -- config root (dict expected). Uses self._config if None (the default)
+		* create -- create path if nonexistent
+		* value -- assign value to the last path element
+		           an empty dict will be created if this is None and create is True
+		"""
 		if path is None:
 			return root
 		elif isinstance ( path, str ):
@@ -166,10 +184,36 @@ class ConfigTree:
 	# --- end of get (...) ---
 
 	def _add_entry ( self, option, value=None, config_root=None ):
+		"""Adds an option to the config.
+
+		arguments:
+		* option -- name of the option as it appears in the (main) config file
+		* value -- value to assign, defaults to None
+		* config_root -- root of the config (a dict), defaults to None which is
+		                 later understood as self._config
+		"""
 
 		def make_and_verify_value ( value_type, value, entryconfig_ref ):
+			"""Prepares the value of a config option so that it can be used
+			in the ConfigTree.
+
+			arguments:
+			* value_type -- type of the value, look above for explanation concerning this
+			* value -- value to verify and transform
+			* entryconfig_ref -- reference to the config entry config
+			"""
 
 			def to_int ( val, fallback_value=-1 ):
+				"""Tries to convert val to an int, returning a fallback value
+				on any error.
+
+				arguments:
+				* val --
+				* fallback_value --
+
+				catches: ValueError in case of an unsuccesful int conversion
+				raises: nothing
+				"""
 				try:
 					ret = int ( val )
 					return ret
@@ -178,6 +222,13 @@ class ConfigTree:
 			# --- end of to_int (...) ---
 
 			def yesno ( val ):
+				"""Tries to canonize an yes or no value to its integer
+				representation. Returns 1 if val means 'yes', 0 if 'no' and
+				-1 otherwise.
+
+				arguments:
+				* val --
+				"""
 				if not val is None:
 					to_check = str ( val ) . lower ()
 					if to_check in [ 'y', 'yes', '1', 'true', 'enabled', 'on' ]:
@@ -190,10 +241,21 @@ class ConfigTree:
 			# --- end of yesno (...) ---
 
 			def fs_path ( val ):
+				"""val is a filesystem path - returns expanded path (~ -> HOME).
+
+				arguments:
+				* val --
+				"""
 				return os.path.expanduser ( val ) if val else None
 			# --- end of fs_path (...) ---
 
 			def fs_file ( val ):
+				""""val is a file - returns expanded path if it is an existent
+				file or it does not exist.
+
+				arguments:
+				* val --
+				"""
 				if val:
 					retval = os.path.expanduser ( val )
 					if os.path.isfile ( retval ) or not os.path.exists ( retval ):
@@ -202,8 +264,25 @@ class ConfigTree:
 				return None
 			# --- end of fs_file (...) ---
 
+			def fs_dir ( val ):
+				"""val is a directory -- returns expanded path if it is an existent
+				dir or it does not exist.
+
+				arguments:
+				* val --
+				"""
+				if val:
+					retval = os.path.expanduser ( val )
+					if os.path.isdir ( retval ) or not os.path.exists ( retval ):
+						return retval
+
+				return None
+			# --- end of fs_dir (...) ---
+
+			# replace whitespace with a single ' '
 			value = ConfigTree.WHITESPACE.sub ( ' ', value )
 
+			# convert value_type into a list of value types
 			if not value_type:
 				return value
 			elif isinstance ( value_type, list ):
@@ -227,7 +306,6 @@ class ConfigTree:
 			# dofunc ( function f, <list or str> v) calls f(x) for every str in v
 			dofunc = lambda f, v : [ f(x) for x in v ] if isinstance ( v, list ) else f(v)
 
-
 			retval = value
 
 			for vtype in vtypes:
@@ -236,26 +314,43 @@ class ConfigTree:
 				else:
 					self.logger.warning ( "unknown value type '" + vtype + "'." )
 
-
 			return retval
 		# --- end of make_and_verify_value (...) ---
 
 
 		real_option = option
 		low_option = option.lower()
+
+		# known option?
 		if option and low_option in ConfigTree.CONFIG_ENTRY_MAP:
-			cref = ConfigTree.CONFIG_ENTRY_MAP [low_option]
 
-			if isinstance ( cref, str ) and cref in ConfigTree.CONFIG_ENTRY_MAP:
-				option = low_option = cref
-				cref = ConfigTree.CONFIG_ENTRY_MAP [cref]
+			original_cref = cref = ConfigTree.CONFIG_ENTRY_MAP [low_option]
+			cref_level = 0
+
+			# check if cref is a link to another entry in CONFIG_ENTRY_MAP
+			while isinstance ( cref, str ):
+				if cref == original_cref and cref_level:
+					self.logger.critical ( "CONFIG_ENTRY_MAP is invalid! circular cref detected." )
+					raise Exception ( "CONFIG_ENTRY_MAP is invalid!" )
+
+				elif cref in ConfigTree.CONFIG_ENTRY_MAP:
+					option = low_option = cref
+					cref = ConfigTree.CONFIG_ENTRY_MAP [cref]
+					cref_level += 1
+				else:
+					self.logger.critical (
+						"CONFIG_ENTRY_MAP is invalid! last cref = " + option +
+						", current cref = " + cref + "."
+					)
+					raise Exception ( "CONFIG_ENTRY_MAP is invalid!" )
 
+			# check if config entry is disabled
 			if cref is None:
 				# deftly ignored
 				return True
 
 
-
+			# determine the config path
 			path = None
 			if 'path' in cref:
 				path = cref ['path']
@@ -264,12 +359,14 @@ class ConfigTree:
 				for n in range ( len ( path ) - 1 ):
 					path [n] = path [n].upper()
 
-
+			# need a valid path
 			if path:
 
+				# verify and convert value if value_type is set
 				if 'value_type' in cref:
 					value = make_and_verify_value ( cref ['value_type'], value, cref )
 
+				# need a valid value
 				if value:
 
 					self.logger.debug (
@@ -278,6 +375,7 @@ class ConfigTree:
 						" and value " + str ( value ) + "."
 					)
 
+					# add option/value to the config
 					self._findpath ( path, config_root, True, value )
 
 					return True
@@ -286,7 +384,11 @@ class ConfigTree:
 						"Option '" + str ( real_option ) +
 						"' has an unusable value '" + str ( value ) + "'."
 					)
+					return False
 			# ---
+
+			self.logger.error ( "Option '" + str ( real_option ) + "' is unusable..." )
+			return False
 		# ---
 
 		self.logger.warning ( "Option '" + str ( real_option ) + "' is unknown." )
@@ -313,10 +415,11 @@ class ConfigTree:
 		# load file
 
 		try:
-			fh = open ( config_file, 'r' )
-			reader = shlex.shlex ( fh )
+			reader.wordchars       += ' ./$()[]:+-@*~'
+			fh                      = open ( config_file, 'r' )
+			reader                  = shlex.shlex ( fh )
 			reader.whitespace_split = False
-			reader.wordchars += ' ./$()[]:+-@*~'
+
 
 			nextline = lambda : ( reader.get_token() for n in range (3) )
 
@@ -333,13 +436,9 @@ class ConfigTree:
 
 				option, equal, value = nextline ()
 
-
-
 			if fh:
 				fh.close ()
 
-			# <TODO>
-
 		except IOError as ioerr:
 			raise
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-04 19:07 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-04 19:07 UTC (permalink / raw
  To: gentoo-commits

commit:     0070a7fb77e1be78cb49cbd043987b9cc87ba50b
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun  4 19:06:52 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun  4 19:06:52 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0070a7fb

config.py: config entry value types explained

---
 roverlay/config.py |   62 +++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index bce721c..ab6dfec 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -3,7 +3,7 @@
 # Distributed under the terms of the GNU General Public License v2
 
 import copy
-import os
+import os.path
 import re
 import sys
 import shlex
@@ -64,8 +64,21 @@ class ConfigTree:
 	# static access to the first created ConfigTree
 	instance = None
 
-	# the list of 'normal' config entries (no special config path) (in lowercase)
-	# the map of config entries
+	# the map of config entries (keep keys in lowercase)
+	# * value_type, you can specify:
+	# ** slist (whitespace-separated list)
+	# ** list (see DEFAULT_LIST_REGEX below)
+	# ** int
+	# ** yesno
+	# ** fs_path (~ will be expanded)
+	# ** fs_file (fs_path + must be a file if it exists)
+	#
+	#   multiple types are generally not supported ('this is an int or a str'),
+	#   but subtypes are (list of yesno), which can be specified by either
+	#   using a list of types ['list', 'yesno'] or by separating the types
+	#   with a colon list:yesno, which is parsed in a left-to-right order.
+	#   Nested subtypes such as list:slist:int:fs_file:list may lead to errors.
+	#
 	CONFIG_ENTRY_MAP = dict (
 		log_level = '',
 		log_console = dict (
@@ -176,6 +189,19 @@ class ConfigTree:
 				return -1
 			# --- end of yesno (...) ---
 
+			def fs_path ( val ):
+				return os.path.expanduser ( val ) if val else None
+			# --- end of fs_path (...) ---
+
+			def fs_file ( val ):
+				if val:
+					retval = os.path.expanduser ( val )
+					if os.path.isfile ( retval ) or not os.path.exists ( retval ):
+						return retval
+
+				return None
+			# --- end of fs_file (...) ---
+
 			value = ConfigTree.WHITESPACE.sub ( ' ', value )
 
 			if not value_type:
@@ -188,23 +214,29 @@ class ConfigTree:
 				self.logger.error ( "Unknown data type for value type." )
 				return value
 
+			# value_type -> function where function accepts one parameter
+			funcmap = {
+				'list'    : ConfigTree.DEFAULT_LIST_REGEX.split,
+				'slist'   : ConfigTree.WHITESPACE.split,
+				'yesno'   : yesno,
+				'int'     : to_int,
+				'fs_path' : fs_path,
+				'fs_file' : fs_file,
+			}
+
+			# dofunc ( function f, <list or str> v) calls f(x) for every str in v
+			dofunc = lambda f, v : [ f(x) for x in v ] if isinstance ( v, list ) else f(v)
+
+
 			retval = value
-			is_list = False
-			for vtype in vtypes:
-				if vtype == 'list':
-					retval = ConfigTree.DEFAULT_LIST_REGEX.split ( retval )
-					is_list = True
-				elif vtype == 'slist':
-					retval = ConfigTree.WHITESPACE.split ( retval )
-					is_list = True
-				elif vtype == 'yesno':
-					retval = [  yesno ( x ) for x in retval ] if is_list else yesno ( retval )
-				elif vtype == 'int':
-					retval = [ to_int ( x ) for x in retval ] if is_list else to_int ( retval )
 
+			for vtype in vtypes:
+				if vtype in funcmap:
+					retval = dofunc ( funcmap [vtype], retval )
 				else:
 					self.logger.warning ( "unknown value type '" + vtype + "'." )
 
+
 			return retval
 		# --- end of make_and_verify_value (...) ---
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-04 19:07 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-04 19:07 UTC (permalink / raw
  To: gentoo-commits

commit:     75c0874ffdaa074891506f759190b133a9490a4f
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun  4 19:05:45 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun  4 19:05:45 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=75c0874f

ebuildjob: metadata.xml todo

---
 roverlay/ebuildjob.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index b6c9456..be8e5e3 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -100,7 +100,7 @@ class EbuildJob:
 		"""
 
 		# TODO move hardcoded entries to config/const
-		# TODO metadata.xml creation
+		# TODO metadata.xml creation (long DESCRIPTION should go into metadata, not the ebuild)
 
 		try:
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-04 15:43 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-04 15:43 UTC (permalink / raw
  To: gentoo-commits

commit:     346f15b80151811fb0813d5f14195ae8d73b4d61
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jun  4 15:42:50 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jun  4 15:42:50 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=346f15b8

roverlay, config: fix typo and add main config reader

	modified:   config.py

---
 roverlay/config.py |  172 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 159 insertions(+), 13 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index 41a98bf..bce721c 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -2,9 +2,11 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import copy
+import os
+import re
 import sys
 import shlex
-import copy
 
 try:
 	import configparser
@@ -13,8 +15,6 @@ except ImportError as running_python2:
 	import ConfigParser as configparser
 
 
-
-
 from roverlay import descriptionfields
 from roverlay import const
 
@@ -51,8 +51,8 @@ class InitialLogger:
 		known from the logging module and its output goes directly to sys.stderr.
 		This can be used until the real logging has been configured.
 		"""
-		self.debug     = lambda x : sys.stderr.write ( "DBG  " + str ( x ) + "\n" )
-		self.info      = lambda x : sys.stderr.write ( "INFO " + str ( x ) + "\n" )
+		self.debug     = lambda x : sys.stdout.write ( "DBG  " + str ( x ) + "\n" )
+		self.info      = lambda x : sys.stdout.write ( "INFO " + str ( x ) + "\n" )
 		self.warning   = lambda x : sys.stderr.write ( "WARN " + str ( x ) + "\n" )
 		self.error     = lambda x : sys.stderr.write ( "ERR  " + str ( x ) + "\n" )
 		self.critical  = lambda x : sys.stderr.write ( "CRIT " + str ( x ) + "\n" )
@@ -64,6 +64,25 @@ class ConfigTree:
 	# static access to the first created ConfigTree
 	instance = None
 
+	# the list of 'normal' config entries (no special config path) (in lowercase)
+	# the map of config entries
+	CONFIG_ENTRY_MAP = dict (
+		log_level = '',
+		log_console = dict (
+			value_type = 'yesno',
+		),
+		log_file = dict (
+			value_type = 'fs_file',
+		),
+		ebuild_header = dict (
+			value_type = 'fs_file',
+		)
+
+	)
+
+	DEFAULT_LIST_REGEX = re.compile ( '\s*[,;]{1}\s*' )
+	WHITESPACE         = re.compile ( '\s+' )
+
 	def __init__ ( self, import_const=True ):
 		"""Initializes an ConfigTree, which is a container for options/config values.
 		values can be stored directly (such as the field_definitions) or in a
@@ -89,19 +108,18 @@ class ConfigTree:
 	# --- end of __init__ (...) ---
 
 
-	def _findpath ( self, path, root=None, create=False ):
+	def _findpath ( self, path, root=None, create=False, value=None ):
 		if path is None:
 			return root
 		elif isinstance ( path, str ):
-			path = path.split ( '.' ) if key else []
+			path = path.split ( '.' ) if path else []
 
 		config_position = self._config if root is None else root
 
 		for k in path:
 			if not k in config_position:
 				if create:
-					config_position [k] = dict ()
-
+					config_position [k] = value if k == path [-1] and value else dict ()
 				else:
 					return None
 
@@ -134,22 +152,130 @@ class ConfigTree:
 
 	# --- end of get (...) ---
 
+	def _add_entry ( self, option, value=None, config_root=None ):
+
+		def make_and_verify_value ( value_type, value, entryconfig_ref ):
+
+			def to_int ( val, fallback_value=-1 ):
+				try:
+					ret = int ( val )
+					return ret
+				except ValueError as verr:
+					return fallback_value
+			# --- end of to_int (...) ---
+
+			def yesno ( val ):
+				if not val is None:
+					to_check = str ( val ) . lower ()
+					if to_check in [ 'y', 'yes', '1', 'true', 'enabled', 'on' ]:
+						return 1
+					elif to_check in [ 'n', 'no', '0', 'false', 'disabled', 'off' ]:
+						return 0
+
+				self.logger.warning ( to_check + " is not a valid yesno value." )
+				return -1
+			# --- end of yesno (...) ---
+
+			value = ConfigTree.WHITESPACE.sub ( ' ', value )
+
+			if not value_type:
+				return value
+			elif isinstance ( value_type, list ):
+				vtypes = value_type
+			elif isinstance ( value_type, str ):
+				vtypes = value_type.split ( ':' )
+			else:
+				self.logger.error ( "Unknown data type for value type." )
+				return value
+
+			retval = value
+			is_list = False
+			for vtype in vtypes:
+				if vtype == 'list':
+					retval = ConfigTree.DEFAULT_LIST_REGEX.split ( retval )
+					is_list = True
+				elif vtype == 'slist':
+					retval = ConfigTree.WHITESPACE.split ( retval )
+					is_list = True
+				elif vtype == 'yesno':
+					retval = [  yesno ( x ) for x in retval ] if is_list else yesno ( retval )
+				elif vtype == 'int':
+					retval = [ to_int ( x ) for x in retval ] if is_list else to_int ( retval )
+
+				else:
+					self.logger.warning ( "unknown value type '" + vtype + "'." )
+
+			return retval
+		# --- end of make_and_verify_value (...) ---
+
+
+		real_option = option
+		low_option = option.lower()
+		if option and low_option in ConfigTree.CONFIG_ENTRY_MAP:
+			cref = ConfigTree.CONFIG_ENTRY_MAP [low_option]
+
+			if isinstance ( cref, str ) and cref in ConfigTree.CONFIG_ENTRY_MAP:
+				option = low_option = cref
+				cref = ConfigTree.CONFIG_ENTRY_MAP [cref]
+
+			if cref is None:
+				# deftly ignored
+				return True
+
+
+
+			path = None
+			if 'path' in cref:
+				path = cref ['path']
+			else:
+				path = low_option.split ( '_' )
+				for n in range ( len ( path ) - 1 ):
+					path [n] = path [n].upper()
+
+
+			if path:
+
+				if 'value_type' in cref:
+					value = make_and_verify_value ( cref ['value_type'], value, cref )
+
+				if value:
+
+					self.logger.debug (
+						"New config entry " + str ( option ) +
+						" with path " + str ( path ) +
+						" and value " + str ( value ) + "."
+					)
+
+					self._findpath ( path, config_root, True, value )
+
+					return True
+				else:
+					self.logger.error (
+						"Option '" + str ( real_option ) +
+						"' has an unusable value '" + str ( value ) + "'."
+					)
+			# ---
+		# ---
+
+		self.logger.warning ( "Option '" + str ( real_option ) + "' is unknown." )
+		return False
+
+	# --- end of _add_entry (...) ---
+
 	def load_config ( self, config_file, start_section='' ):
 		"""Loads a config file and integrates its content into the config tree.
 		Older config entries may be overwritten.
 
 		arguments:
 		config_file   -- path to the file that should be read
-		start_section -- relative root in the config tree as str or ref
+		start_section -- relative root in the config tree as str
 		"""
 
 		config_root = None
 		if start_section:
 			if isinstance ( start_section, str ):
 				config_root = self._findpath ( start_section, None, True )
-			elif isinstance ( start_section, dict ):
-				config_root = start_section
-			else
+			else:
 				raise Exception ("bad usage")
 
 		# load file
@@ -157,6 +283,26 @@ class ConfigTree:
 		try:
 			fh = open ( config_file, 'r' )
 			reader = shlex.shlex ( fh )
+			reader.whitespace_split = False
+			reader.wordchars += ' ./$()[]:+-@*~'
+
+			nextline = lambda : ( reader.get_token() for n in range (3) )
+
+			option, equal, value = nextline ()
+
+			while equal == '=' or not ( option == value == reader.eof ):
+				if equal == '=':
+					self._add_entry ( option, value, config_root )
+				else:
+					self.logger.warning (
+						"In '" + config_file + "', cannot parse this line: '" +
+						str ( option ) + str ( equal ) + str ( value ) + "'."
+					)
+
+				option, equal, value = nextline ()
+
+
+
 			if fh:
 				fh.close ()
 



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

commit:     6571bf138322945ba7712479147516fd509fb255
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun  1 16:18:44 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun  1 16:18:44 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=6571bf13

remove debug print in descriptionreader

---
 roverlay/descriptionreader.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/roverlay/descriptionreader.py b/roverlay/descriptionreader.py
index 2af4372..762dec0 100644
--- a/roverlay/descriptionreader.py
+++ b/roverlay/descriptionreader.py
@@ -103,7 +103,7 @@ class DescriptionReader:
 
 		# join values to a single string
 		for field_name in self.field_definition.get_fields_with_flag ( 'joinValues' ):
-			print ( "?, ".join ( [ field_name, 'join', str ( read_data ) ] ) )
+
 			if field_name in read_data:
 				read_data [field_name] = ' ' . join ( read_data [field_name] )
 



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

commit:     d0fa945b8c81fedbcc02dc3f1e3e824a5b7170cc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun  1 16:19:03 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun  1 16:19:03 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d0fa945b

config: faster lookup

---
 roverlay/config.py |   74 ++++++++++++++++++++++++++++++++++++++++++---------
 roverlay/const.py  |   15 +++-------
 2 files changed, 66 insertions(+), 23 deletions(-)

diff --git a/roverlay/config.py b/roverlay/config.py
index b0bf7a3..41a98bf 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -4,6 +4,7 @@
 
 import sys
 import shlex
+import copy
 
 try:
 	import configparser
@@ -81,13 +82,36 @@ class ConfigTree:
 
 		self.parser = dict()
 
-		self._config = const.clone() if import_const else None
+		self._config = const.clone() if import_const else dict ()
 		self._const_imported = import_const
 		self._field_definitions = None
 
 	# --- end of __init__ (...) ---
 
 
+	def _findpath ( self, path, root=None, create=False ):
+		if path is None:
+			return root
+		elif isinstance ( path, str ):
+			path = path.split ( '.' ) if key else []
+
+		config_position = self._config if root is None else root
+
+		for k in path:
+			if not k in config_position:
+				if create:
+					config_position [k] = dict ()
+
+				else:
+					return None
+
+			config_position = config_position [k]
+
+		return config_position
+
+	# --- end of _findpath (...) ---
+
+
 	def get ( self, key, fallback_value=None ):
 		"""Searches for key in the ConfigTree and returns its value.
 		Searches in const if ConfigTree does not contain the requested key and
@@ -98,19 +122,10 @@ class ConfigTree:
 		* fallback_value --
 		"""
 		if self._config:
-			config_path = key.split ( '.' )
-			config_path.reverse ()
-
-			config_position = self._config
-			while len ( config_path ) and config_position:
-				next_key = config_path.pop ()
-				if next_key in config_position:
-					config_position = config_position [next_key]
-				else:
-					config_position = None
+			config_value = self._findpath ( key )
 
-			if config_position:
-				return config_position
+			if config_value:
+				return config_value
 
 		if self._const_imported:
 			return fallback_value
@@ -119,6 +134,39 @@ class ConfigTree:
 
 	# --- end of get (...) ---
 
+	def load_config ( self, config_file, start_section='' ):
+		"""Loads a config file and integrates its content into the config tree.
+		Older config entries may be overwritten.
+
+		arguments:
+		config_file   -- path to the file that should be read
+		start_section -- relative root in the config tree as str or ref
+		"""
+
+		config_root = None
+		if start_section:
+			if isinstance ( start_section, str ):
+				config_root = self._findpath ( start_section, None, True )
+			elif isinstance ( start_section, dict ):
+				config_root = start_section
+			else
+				raise Exception ("bad usage")
+
+		# load file
+
+		try:
+			fh = open ( config_file, 'r' )
+			reader = shlex.shlex ( fh )
+			if fh:
+				fh.close ()
+
+			# <TODO>
+
+		except IOError as ioerr:
+			raise
+
+	# --- end of load_config (...) ---
+
 	def load_field_definition ( self, def_file, lenient=False ):
 		"""Loads a field definition file. Please see the example file for format
 		details.

diff --git a/roverlay/const.py b/roverlay/const.py
index 32630cf..527939b 100644
--- a/roverlay/const.py
+++ b/roverlay/const.py
@@ -31,21 +31,16 @@ _CONSTANTS = dict (
 
 def lookup ( key, fallback_value=None ):
 	path = key.split ( '.' )
-	path.reverse ()
 
 	const_position = _CONSTANTS
 
-	while len ( path ) and const_position:
-		next_key = path.pop ()
-		if next_key in const_position:
-			const_position = const_position [next_key]
+	for k in path:
+		if k in const_position:
+			const_position = const_position [k]
 		else:
-			const_position = None
+			return fallback_value
 
-	if const_position:
-		return const_position
-	else:
-		return fallback_value
+	return const_position
 
 def clone ( ):
 	return copy.deepcopy ( _CONSTANTS )



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-06-01 15:46 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-06-01 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     ac0b226fd7d16dad7a4b8d30b4293fe401406c1c
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun  1 14:56:09 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun  1 14:56:09 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ac0b226f

2012-01-06:
	* description field definition is now configurable

	modified:   roverlay/__init__.py
	modified:   roverlay/config.py
	new file:   roverlay/const.py
	modified:   roverlay/descriptionfields.py
	renamed:    roverlay/fileio.py -> roverlay/descriptionreader.py
	modified:   roverlay/ebuild.py
	modified:   roverlay/ebuildjob.py
	deleted:    roverlay/tmpconst.py

---
 roverlay/__init__.py                         |    5 +
 roverlay/config.py                           |  164 ++++++++++++-
 roverlay/const.py                            |   51 ++++
 roverlay/descriptionfields.py                |  343 +++++++++++++++++++++++---
 roverlay/{fileio.py => descriptionreader.py} |  248 ++++++-------------
 roverlay/ebuild.py                           |    5 +-
 roverlay/ebuildjob.py                        |   15 +-
 roverlay/tmpconst.py                         |  108 --------
 8 files changed, 615 insertions(+), 324 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index b1557ef..f50cec9 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -4,6 +4,11 @@
 
 import logging
 
+
+from roverlay import config
+
+config.access().load_field_definition ( 'description_fields.conf' )
+
 logging.basicConfig (
 	level=logging.DEBUG,
 	filename='roverlay.log',

diff --git a/roverlay/config.py b/roverlay/config.py
index 248fc22..b0bf7a3 100644
--- a/roverlay/config.py
+++ b/roverlay/config.py
@@ -3,20 +3,53 @@
 # Distributed under the terms of the GNU General Public License v2
 
 import sys
-
-from roverlay import descriptionfields
+import shlex
 
 try:
 	import configparser
-except ImportError:
+except ImportError as running_python2:
+	# configparser is named ConfigParser in python2
 	import ConfigParser as configparser
 
+
+
+
+from roverlay import descriptionfields
+from roverlay import const
+
+
+
+
 def access():
+	"""Returns the ConfigTree."""
 	return ConfigTree() if ConfigTree.instance is None else ConfigTree.instance
+# --- end of access (...) ---
+
+
+def get ( key, fallback_value=None ):
+	"""Searches for key in the ConfigTree and returns its value if possible,
+	else fallback_value.
+	'key' is a config path [<section>[.<subsection>*]]<option name>.
+
+	arguments:
+	* key --
+	* fallback_value --
+	"""
+	if fallback_value:
+		return access().get ( key, fallback_value )
+	else:
+		return access().get ( key )
+# --- end of get (...) ---
+
 
 class InitialLogger:
 
 	def __init__ ( self ):
+		"""Initializes an InitialLogger.
+		It implements the debug/info/warning/error/critical/exception methods
+		known from the logging module and its output goes directly to sys.stderr.
+		This can be used until the real logging has been configured.
+		"""
 		self.debug     = lambda x : sys.stderr.write ( "DBG  " + str ( x ) + "\n" )
 		self.info      = lambda x : sys.stderr.write ( "INFO " + str ( x ) + "\n" )
 		self.warning   = lambda x : sys.stderr.write ( "WARN " + str ( x ) + "\n" )
@@ -24,11 +57,23 @@ class InitialLogger:
 		self.critical  = lambda x : sys.stderr.write ( "CRIT " + str ( x ) + "\n" )
 		self.exception = lambda x : sys.stderr.write ( "EXC! " + str ( x ) + "\n" )
 
+	# --- end of __init__ (...) ---
+
 class ConfigTree:
 	# static access to the first created ConfigTree
 	instance = None
 
-	def __init__ ( self ):
+	def __init__ ( self, import_const=True ):
+		"""Initializes an ConfigTree, which is a container for options/config values.
+		values can be stored directly (such as the field_definitions) or in a
+		tree-like { section -> subsection[s] -> option = value } structure.
+		Config keys cannot contain dots because they're used as config path
+		separator.
+
+		arguments:
+		* import_const -- whether to deepcopy constants into the config tree or
+		                  not. Copying allows faster lookups.
+		"""
 		if ConfigTree.instance is None:
 			ConfigTree.instance = self
 
@@ -36,8 +81,52 @@ class ConfigTree:
 
 		self.parser = dict()
 
+		self._config = const.clone() if import_const else None
+		self._const_imported = import_const
+		self._field_definitions = None
+
+	# --- end of __init__ (...) ---
+
+
+	def get ( self, key, fallback_value=None ):
+		"""Searches for key in the ConfigTree and returns its value.
+		Searches in const if ConfigTree does not contain the requested key and
+		returns the fallback_value if key not found.
+
+		arguments:
+		* key --
+		* fallback_value --
+		"""
+		if self._config:
+			config_path = key.split ( '.' )
+			config_path.reverse ()
+
+			config_position = self._config
+			while len ( config_path ) and config_position:
+				next_key = config_path.pop ()
+				if next_key in config_position:
+					config_position = config_position [next_key]
+				else:
+					config_position = None
+
+			if config_position:
+				return config_position
+
+		if self._const_imported:
+			return fallback_value
+		else:
+			return const.lookup ( key, fallback_value )
+
+	# --- end of get (...) ---
 
 	def load_field_definition ( self, def_file, lenient=False ):
+		"""Loads a field definition file. Please see the example file for format
+		details.
+
+		arguments:
+		* def_file -- file (str) to read, this can be a list of str if lenient is True
+		* lenient  -- if True: do not fail if a file cannot be read; defaults to False
+		"""
 		if not 'field_def' in self.parser:
 			self.parser ['field_def'] = configparser.SafeConfigParser ( allow_no_value=True )
 
@@ -57,4 +146,71 @@ class ConfigTree:
 			self.logger.exception ( mshe )
 			raise
 
+	# --- end of load_field_definition (...) ---
+
+
+	def get_field_definition ( self, force_update=False ):
+		"""Gets the field definition stored in this ConfigTree.
+
+		arguments:
+		* force_update -- enforces recreation of the field definition data.
+		"""
+		if force_update or not self._field_definitions:
+			self._field_definitions = self._make_field_definition ()
+
+		return self._field_definitions
+
+	# --- end of get_field_definition (...) ---
+
+
+	def _make_field_definition ( self ):
+		"""Creates and returns field definition data. Please see the example
+		field definition config file for details.
+		"""
+
+		def get_list ( value_str ):
+			if value_str is None:
+				return []
+			else:
+				l = value_str.split ( ', ' )
+				return [ e for e in l if e.strip() ]
+
+		if not 'field_def' in self.parser:
+			return None
+
+		fdef = descriptionfields.DescriptionFields ()
+
+		for field_name in self.parser ['field_def'].sections():
+			field = descriptionfields.DescriptionField ( field_name )
+			for option, value in self.parser ['field_def'].items ( field_name, 1 ):
+
+				if option == 'alias' or option == 'alias_withcase':
+					for alias in get_list ( value ):
+						field.add_simple_alias ( alias, True )
+
+				elif option == 'alias_nocase':
+					for alias in get_list ( value ):
+						field.add_simple_alias ( alias, False )
+
+				elif option == 'default_value':
+					field.set_default_value ( value )
+
+				elif option == 'allowed_value':
+					field.add_allowed_value ( value )
+
+				elif option == 'allowed_values':
+					for item in get_list ( value ):
+						field.add_allowed_value ( item )
+
+				elif option == 'flags':
+					for flag in get_list ( value ):
+						field.add_flag ( flag )
+				else:
+					# treat option as flag
+					field.add_flag ( option )
+
+			fdef.add ( field )
+
+		return fdef
 
+	# --- end of _make_field_definition (...) ---

diff --git a/roverlay/const.py b/roverlay/const.py
new file mode 100644
index 0000000..32630cf
--- /dev/null
+++ b/roverlay/const.py
@@ -0,0 +1,51 @@
+# R Overlay -- constants
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import copy
+import time
+
+_CONSTANTS = dict (
+	DESCRIPTION = dict (
+		field_separator  = ':',
+		comment_char     = '#',
+		list_split_regex = '\s*[,;]{1}\s*',
+		file_name        = 'DESCRIPTION',
+	),
+	R_PACKAGE = dict (
+		suffix_regex       = '[.](tgz|tbz2|tar|(tar[.](gz|bz2)))',
+		name_ver_separator = '_',
+	),
+	EBUILD = dict (
+		indent         = '\t',
+		default_header = [	'# Copyright 1999-' + str ( time.gmtime() [0] ) + ' Gentoo Foundation',
+									'# Distributed under the terms of the GNU General Public License v2',
+									'# $Header: $',
+									'',
+									'EAPI=4',
+									'',
+									'inherit R-packages'
+								],
+	)
+)
+
+def lookup ( key, fallback_value=None ):
+	path = key.split ( '.' )
+	path.reverse ()
+
+	const_position = _CONSTANTS
+
+	while len ( path ) and const_position:
+		next_key = path.pop ()
+		if next_key in const_position:
+			const_position = const_position [next_key]
+		else:
+			const_position = None
+
+	if const_position:
+		return const_position
+	else:
+		return fallback_value
+
+def clone ( ):
+	return copy.deepcopy ( _CONSTANTS )

diff --git a/roverlay/descriptionfields.py b/roverlay/descriptionfields.py
index 9c028c2..72175cb 100644
--- a/roverlay/descriptionfields.py
+++ b/roverlay/descriptionfields.py
@@ -2,39 +2,95 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-
-# split from tmpconst / fileio to make configuration possible, but TODO
-
 class DescriptionField:
+	"""Configuration for a field in the R package description file."""
 
 	def __init__ ( self, name ):
+		"""Initializes a DescriptionField with a valid(!) name.
+
+		arguments:
+		* name -- name of the field, has to be True (neither empty nor None)
+
+		raises: Exception if name not valid
+		"""
+
 		if not name:
 			raise Exception ( "description field name is empty." )
 
 		self.name = name
 
+	# --- end of __init__ (...) ---
 
 
 	def get_name ( self ):
+		"""Returns the name of this DescriptionField."""
 		return self.name
 
-	def add_flag ( self, flag, lowercase=True ):
-		if not hasattr ( self, flags ):
+	# --- end of get_name (...) ---
+
+
+	def add_flag ( self, flag ):
+		"""Adds a flag to this DescriptionField. Flags are always stored in
+		their lowercase form.
+
+		arguments:
+		* flag -- name of the flag
+		"""
+		if not hasattr ( self, 'flags' ):
 			self.flags = set ()
 
-		self.flags.add ( flag, flag.lower() if lowercase else flag )
+		self.flags.add ( flag.lower() )
 
 		return None
 
+	# --- end of add_flag (...) ---
+
+
+	def add_allowed_value ( self, value ):
+		"""Adds an allowed value to this DescriptionField, which creates a
+		value whitelist for it. You can later check if a value is allowed using
+		value_allowed (<value> [, <case insensitive?>]).
+
+		arguments:
+		* value -- allowed value
+		"""
+
+		if not hasattr ( self, 'allowed_values' ):
+			self.allowed_values = set ()
+
+		self.allowed_values.add ( value )
+
+		return None
+
+	# --- end of add_allowed_value (...) ---
+
 
 	def del_flag ( self, flag ):
-		if hasattr ( self, flags ):
-			self.flags.discard ( flag )
+		"""Removes a flag from this DescriptionField. Does nothing if the flag
+		does not exist.
+		"""
+		if hasattr ( self, 'flags' ):
+			self.flags.discard ( flag.lower() )
 		return None
 
+	# --- end of del_flag (...) ---
+
 
 	def add_alias ( self, alias, alias_type='withcase' ):
-		if not hasattr ( self, aliases ):
+		"""Adds an alias for this DescriptionField's name. This can also be used
+		to combine different fields ('Description' and 'Title') or to fix
+		typos ('Depend' -> 'Depends').
+
+		arguments:
+		* alias -- alias name
+		* alias_type -- type of the alias; currently this is limited to
+		                 'withcase' : alias is case sensitive,
+		                 'nocase'   : alias is case insensitive
+		                any other type leads to an error
+
+		raises: KeyError if alias_type unknown.
+		"""
+		if not hasattr ( self, 'aliases' ):
 			self.aliases = dict ()
 
 		to_add = dict (
@@ -50,37 +106,83 @@ class DescriptionField:
 
 		return None
 
+	# --- end of add_alias (...) ---
 
 
 	def add_simple_alias ( self, alias, withcase=True ):
-		if withcase:
-			return self.add_alias ( alias, alias_type='withcase' )
-		else:
-			return self.add_alias ( alias, alias_type='nocase' )
+		"""Adds an alias to this DescriptionField. Its type is either withcase
+		or nocase. See add_alias (...) for details.
+
+		arguments:
+		alias --
+		withcase -- if True (the default): alias_type is withcase, else nocase
+
+		raises: KeyError (passed from add_alias (...))
+		"""
+		return self.add_alias ( alias, ( 'withcase' if withcase else 'nocase' ) )
 
+	# --- end of add_simple_alias (...) ---
 
 
 	def get_default_value ( self ):
-		if hasattr ( self, 'default_value' ):
-			return self.default_value
-		else:
-			return None
+		"""Returns the default value for this DescriptionField if it exists,
+		else None.
+		"""
+		return self.default_value if hasattr ( self, 'default_value' ) else None
 
+	# --- end of get_default_value (...) ---
+
+
+	def set_default_value ( self, value ):
+		"""Sets the default value for this this DescriptionField.
+
+		arguments:
+		* value -- new default value
+		"""
+		self.default_value = value
+
+	# --- end of set_default_value (...) ---
+
+
+	def get_flags ( self ):
+		"""Returns the flags of this DescriptionField or an empty list (=no flags)."""
+		return self.flags if hasattr ( self, 'flags' ) else []
+
+	# --- end of get_flags (...) ---
+
+
+	def get_allowed_values ( self ):
+		"""Returns the allowed values of this DescriptionField or an empty list,
+		which should be interpreted as 'no value restriction'.
+		"""
+		return self.allowed_values if hasattr ( self, 'allowed_values' ) else []
+
+	# --- end of get_allowed_values (...) ---
 
-	def get ( self, key, fallback_value=None ):
-		if hasattr ( self, key ):
-			return self.key
-		else:
-			return fallback_value
 
 	def matches ( self, field_identifier ):
+		"""Returns whether field_identifier equals the name of this DescriptionField.
+
+		arguments:
+		* field_identifier --
+		"""
 		return bool ( self.name == field_identifier ) if field_identifier else False
 
+	# --- end of matches (...) ---
+
+
 	def matches_alias ( self, field_identifier ):
+		"""Returns whether field_identifier equals any alias of this DescriptionField.
+
+		arguments:
+		* field_identifier --
+		"""
 
 		if not field_identifier:
+			# bad identifier
 			return False
-		if not hasattr ( self, aliases ):
+		elif not hasattr ( self, aliases ):
+			# no aliases
 			return False
 
 		if 'withcase' in self.aliases:
@@ -92,30 +194,211 @@ class DescriptionField:
 			if field_id_lower in self.aliases ['nocase']:
 				return True
 
-	def has_flag ( self, flag, lowercase=True ):
-		if not hasattr ( self, flags ):
+	# --- end of matches_alias (...) ---
+
+
+	def has_flag ( self, flag  ):
+		"""Returns whether this DescriptionField has the given flag.
+
+		arguments:
+		* flag --
+		"""
+		if not hasattr ( self, 'flags' ):
 			return False
 
-		return bool ( (flag.lower() if lowercase else flag) in self.flags )
+		return bool ( flag.lower() in self.flags )
+
+	def value_allowed ( self, value, nocase=True ):
+		"""Returns whether value is allowed for this DescriptionField.
+
+		arguments:
+		* value -- value to check
+		* nocase -- if True (the default): be case insensitive
+		"""
+		allowed_values = self.get_allowed_values ()
+
+		if not allowed_values:
+			return True
+		elif nocase:
+			lowval = value.lower()
+			for allowed in allowed_values:
+				if allowed.lower() == lowval:
+					return True
+
+		else:
+			return bool ( value in allowed_values )
+
+		return False
+
+	# --- end of has_flag (...) ---
+
+# --- end of DescriptionField ---
+
 
 class DescriptionFields:
+	"""DescriptionFields stores several instances of DescriptionField and provides
+	'search in all' methods such as get_fields_with_flag (<flag>).
+	"""
 
 	def __init__ ( self ):
-		fields = dict ()
+		"""Initializes an DescriptionFields object."""
+		self.fields = dict ()
+		# result 'caches'
+		## flag -> [<fields>]
+		self._fields_by_flag   = None
+		## option -> [<fields>]
+		self._fields_by_option = None
+
+	# --- end of __init__ (...) ---
+
 
 	def add ( self, desc_field ):
+		"""Adds an DescriptionField. Returns 1 desc_field was a DescriptionField
+		and has been added as obj ref, 2 if a new DescriptionField with
+		name=desc_field has been created and added and 0 if this was not
+		possible.
+
+		arguments:
+		* desc_field -- this can either be a DescriptionField or a name.
+		"""
 		if desc_field:
 			if isinstance ( desc_field, DescriptionField ):
-				fields [desc_field.get_name()] = desc_field
+				self.fields [desc_field.get_name()] = desc_field
 				return 1
 			elif isinstance ( desc_field, str ):
-				fields [desc_field] = DescriptionField ( desc_field )
+				self.fields [desc_field] = DescriptionField ( desc_field )
 				return 2
 
 		return 0
 
+	# --- end of add (...) ---
+
+
 	def get ( self, field_name ):
+		"""Returns the DescriptionField to which field_name belongs to.
+		This method does, unlike others in DescriptionFields, return a
+		reference to the matching DescriptionField object, not the field name!
+		Returns None if field_name not found.
+
+		arguments:
+		* field_name --
+		"""
+
 		return self.fields [field_name] if field_name in self.fields else None
 
-	# ... TODO
+	# --- end of get (...) ---
+
+
+	def find_field ( self, field_name ):
+		"""Determines the name of the DescriptionField to which field_name belongs
+		to. Returns the name of the matching field or None.
+
+		arguments:
+		* field_name --
+		"""
+
+		field = get ( field_name )
+		if field is None:
+			for field in self.fields:
+				if field.matches_alias ( field_name ):
+					return field.get_name ()
+		else:
+			return field.get_name ()
+
+	# --- end of find_field (...) ---
+
+
+	def _field_search ( self ):
+		"""Scans all stored DescriptionField(s) and creates fast-accessible
+		data to be used in get_fields_with_<sth> (...).
+		"""
+		flagmap   = dict ()
+		optionmap = dict (
+			defaults       = dict (),
+			allowed_values = set ()
+		)
+
+		for field_name in self.fields.keys():
+
+			d = self.fields [field_name].get_default_value()
+			if not d is None:
+				optionmap ['defaults'] [field_name] = d
+
+			if self.fields [field_name].get_allowed_values():
+				optionmap ['allowed_values'].add ( field_name )
+
+			for flag in self.fields [field_name].get_flags():
+				if not flag in flagmap:
+					flagmap [flag] = set ()
+				flagmap [flag].add ( field_name )
+
+		self._fields_by_flag   = flagmap
+		self._fields_by_option = optionmap
+		return None
+
+	# --- end of _field_search (...) ---
+
+
+	def get_fields_with_flag ( self, flag, force_update=False ):
+		"""Returns the names of the fields that have the given flag.
+
+		arguments:
+		* flag --
+		* force_update -- force recreation of data
+		"""
+		if force_update or self._fields_by_flag is None:
+			self._field_search ()
+
+		flag = flag.lower()
+
+		if flag in self._fields_by_flag:
+			return self._fields_by_flag [flag]
+		else:
+			return []
+
+	# --- end of get_fields_with_flag (...) ---
+
+
+	def get_fields_with_option ( self, option, force_update=False ):
+		"""Returns a struct with fields that have the given option. The actual
+		data type depends on the requested option.
+
+		arguments:
+		* option --
+		* force_update -- force recreation of data
+		"""
+		if force_update or self._fields_by_option is None:
+			self._field_search ()
+
+		if option in self._fields_by_option:
+			return self._fields_by_option [option]
+		else:
+			return []
+
+	# --- end of get_field_with_option (...) ---
+
+
+	def get_fields_with_default_value ( self, force_update=False ):
+		"""Returns a dict { '<field name>' -> '<default value>' } for all
+		fields that have a default value.
+
+		arguments:
+		* force_update -- force recreation of data
+		"""
+		return self.get_fields_with_option ( 'defaults', force_update )
+
+	# --- end of get_fields_with_default_value (...) ---
+
+
+	def get_fields_with_allowed_values ( self, force_update=False ):
+		"""Returns a set { <field name> } for all fields that allow only
+		certain values.
+
+		arguments:
+		* force_update -- force recreation of data
+		"""
+		return self.get_fields_with_option ( 'allowed_values', force_update )
+
+	# --- end of get_fields_with_allowed_values (...) ---
 
+# --- end of DescriptionFields ---

diff --git a/roverlay/fileio.py b/roverlay/descriptionreader.py
similarity index 54%
rename from roverlay/fileio.py
rename to roverlay/descriptionreader.py
index 5c01527..2af4372 100644
--- a/roverlay/fileio.py
+++ b/roverlay/descriptionreader.py
@@ -1,4 +1,4 @@
-# R Overlay -- file in/out
+# R Overlay -- description reader
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
@@ -7,21 +7,25 @@ import tarfile
 import logging
 import os.path
 
-
-# temporary import until config and real constants are implemented
-from roverlay import tmpconst as const
+from roverlay import config
+from roverlay import descriptionfields
 
 class DescriptionReader:
 	"""Description Reader"""
 
 	LOGGER = logging.getLogger ( 'DescriptionReader' )
 
+
 	def __init__ ( self, package_file, read_now=False ):
 		"""Initializes a DESCRIPTION file reader."""
 
-		self.fileinfo  = self.make_fileinfo ( package_file )
-		self.logger    = DescriptionReader.LOGGER.getChild ( self.get_log_name() )
-		self.desc_data = None
+		if not config.access().get_field_definition():
+			raise Exception ( "Field definition is missing, cannot initialize DescriptionReader." )
+
+		self.field_definition = config.access().get_field_definition()
+		self.fileinfo         = self.make_fileinfo ( package_file )
+		self.logger           = DescriptionReader.LOGGER.getChild ( self.get_log_name() )
+		self.desc_data        = None
 
 
 		if read_now:
@@ -30,10 +34,13 @@ class DescriptionReader:
 	# --- end of __init__ (...) ---
 
 	def get_log_name ( self ):
+		"""Returns a logging name that can be used in other modules."""
 		try:
 			return self.fileinfo ['filename']
 		except Exception as any_exception:
 			return '__undef__'
+	# --- end of get_log_name (...) ---
+
 
 	def get_desc ( self, run_if_unset=True ):
 		if self.desc_data is None:
@@ -58,10 +65,11 @@ class DescriptionReader:
 
 		package_file = os.path.basename ( filepath )
 
-		filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
+		filename = re.sub ( config.get ( 'R_PACKAGE.suffix_regex' ) + '$', '', package_file )
 
-		# todo move that separator to const
-		package_name, sepa, package_version = filename.partition ( '_' )
+		package_name, sepa, package_version = filename.partition (
+			config.get ( 'R_PACKAGE.name_ver_separator', '_' )
+		)
 
 		if not sepa:
 			# file name unexpected, tarball extraction will (probably) fail
@@ -78,7 +86,6 @@ class DescriptionReader:
 
 	# --- end of make_fileinfo (...) ---
 
-
 	def _parse_read_data ( self, read_data ):
 		"""Verifies and parses/fixes read data.
 
@@ -86,80 +93,42 @@ class DescriptionReader:
 		* read_data -- data from file, will be modified
 		"""
 
-		def get_fields_with_flag ( flag, foce_update=False ):
-
-			matching_fields = []
-
-			field = None
-			for field in const.DESCRIPTION_FIELD_MAP.keys():
-				if flag is None:
-					matching_fields.append ( field )
-
-				elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-					if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
-						matching_fields.append ( field )
-
-			del field
-			return matching_fields
-
-		# --- end of get_fields_with_flag (...) ---
-
-		def value_in_strlist ( _val, _list, case_insensitive=True ):
-			"""Returns true if value is in the given list."""
-			el = None
-			if case_insensitive:
-				lowval = _val.lower()
-				for el in _list:
-					if el.lower() == lowval:
-						return True
-				del lowval
-			else:
-				for el in _list:
-					if el == _val:
-						return True
-
-			del el
-			return False
-		# --- end of value_in_strlist (...) ---
-
-		field = None
 
 		# insert default values
-		for field in const.DESCRIPTION_FIELD_MAP.keys():
-			if not field in read_data and 'default_value' in const.DESCRIPTION_FIELD_MAP [field]:
-				read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
+		default_values = self.field_definition.get_fields_with_default_value()
+		for field_name in default_values.keys():
+			if not field_name in read_data:
+				read_data [field_name] = default_values [field_name]
+
 
 		# join values to a single string
-		for field in get_fields_with_flag ( 'joinValues' ):
-			if field in read_data.keys():
-				read_data [field] = ' ' . join ( read_data [field] )
+		for field_name in self.field_definition.get_fields_with_flag ( 'joinValues' ):
+			print ( "?, ".join ( [ field_name, 'join', str ( read_data ) ] ) )
+			if field_name in read_data:
+				read_data [field_name] = ' ' . join ( read_data [field_name] )
 
 		# ensure that all mandatory fields are set
-		missing_fields = list()
+		missing_fields = set ()
 
-		for field in get_fields_with_flag ( 'mandatory' ):
-			if field in read_data:
-				if not len (read_data [field]):
-					missing_fields.append ( field )
+		for field_name in self.field_definition.get_fields_with_flag ( 'mandatory' ):
+			if field_name in read_data:
+				if read_data [field_name] is None or len ( read_data [field_name] ) < 1:
+					missing_fields.add ( field_name )
+				#else: ok
 			else:
-				missing_fields.append ( field )
-
-
+				missing_fields.add ( field_name )
 
 
 		# check for fields that allow only certain values
-		unsuitable_fields = dict()
+		unsuitable_fields = set()
 
-		for field in read_data.keys():
-			if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
-				if not value_in_strlist (
-							read_data [field],
-							const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
-						):
-					unsuitable_fields.append [field] = read_data [field]
-
-		del field
+		restricted_fields = self.field_definition.get_fields_with_allowed_values()
+		for field_name in restricted_fields:
+			if field_name in read_data:
+				if not self.field_definition.get ( field_name ).value_allowed ( read_data [field_name] ):
+					unsuitable_fields.add ( field_name )
 
+		# summarize results
 		valid = not bool ( len ( missing_fields ) or len ( unsuitable_fields ) )
 		if not valid:
 			self.logger.info ( "Cannot use R package" ) # name?
@@ -200,27 +169,6 @@ class DescriptionReader:
 			multiple values arranged in a list (dep0, dep1 [, depK]*).
 			"""
 
-			def check_fieldflag ( field, flag_to_check=None ):
-				"""Checks if the given field has the specified flag and returns a bool.
-
-				arguments:
-				* field -- name of the field that should be checked
-				* flag_to_check -- name of the flag to check; optional, defaults to None
-
-				This method acts as 'field has any flags?' if flag_to_check is None (its default value).
-				"""
-
-				if field in const.DESCRIPTION_FIELD_MAP:
-					if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-						if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
-							return True
-						elif flag_to_check is None:
-							# 'flags' exist, return true
-							return True
-
-				return False
-			# --- end of check_fieldflag (...) ---
-
 			svalue_str = value_str.strip()
 
 			if not svalue_str:
@@ -231,16 +179,17 @@ class DescriptionReader:
 				# default return if no context given
 				return [ svalue_str ]
 
-			elif check_fieldflag ( field_context ):
-				# value str is not empty and have flags for field_context, check these
-
-				if check_fieldflag ( field_context, 'isList' ):
-						# split up this list (that is separated by commata and/or semicolons)
-						return re.split (const.DESCRIPTION_LIST_SPLIT_REGEX, svalue_str, 0)
+			elif field_context in self.field_definition.get_fields_with_flag ( 'isList' ):
+					# split up this list (that is separated by commata and/or semicolons)
+					return re.split (
+						config.get ( 'DESCRIPTION.list_split_regex' ),
+						svalue_str,
+						0
+					)
 
-				elif check_fieldflag ( field_context, 'isWhitespaceList' ):
-						# split up this list (that is separated whitespace)
-						return re.split ( '\s+', svalue_str, 0 )
+			elif field_context in self.field_definition.get_fields_with_flag ( 'isWhitespaceList' ):
+					# split up this list (that is separated whitespace)
+					return re.split ( '\s+', svalue_str, 0 )
 
 
 			# default return
@@ -275,9 +224,12 @@ class DescriptionReader:
 				# filepath is a tarball, open tar handle + file handle
 				th = tarfile.open ( filepath, 'r' )
 				if pkg_name:
-					fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
+					fh = th.extractfile ( os.path.join (
+						pkg_name,
+						config.get ( 'DESCRIPTION.file_name' )
+						) )
 				else:
-					fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
+					fh = th.extractfile ( config.get ( 'DESCRIPTION.file_name' ) )
 
 				# have to decode the lines
 				read = lambda lines : [ line.decode().rstrip() for line in lines ]
@@ -298,60 +250,9 @@ class DescriptionReader:
 
 		# --- end of get_desc_from_file (...) ---
 
-		def find_field ( field_identifier ):
-			"""Determines the real name of a field.
-
-			arguments:
-			* field_identifier -- name of the field as it appears in the DESCRIPTION file
-
-			At first, it is checked whether field_identifier matches the name of
-			a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
-			Then, a new iteration over the field map compares field_identifier
-			with all aliases until the first case-(in)sensitive match (-> immediate return).
-			None will be returned if none of the above searches succeed.
-
-			In other words: this method decides whether a field_identifier will be used and if so,
-			with which name.
-			"""
-
-			# save some time by prevent searching if field_id is empty
-			if not field_identifier:
-				return None
-
-			# search for real field names first
-			for field in const.DESCRIPTION_FIELD_MAP.keys():
-				if field_identifier == field:
-					return field
-
-			field_id_lower = field_identifier.lower()
-
-			for field in const.DESCRIPTION_FIELD_MAP.keys():
-
-				# does extra information (-> alias(es)) for this field exist?
-				if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
-
-					if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-						for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
-							if field_identifier == alias:
-								return field
-
-					if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-						for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
-							if field_id_lower == alias.lower():
-								return field
-
-					#if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-
-			# returning None if no valid field identifier matches
-			return None
-
-		# --- end of find_field (...) ---
-
-
 		self.desc_data = None
 		read_data = dict ()
 
-
 		try:
 			desc_lines = get_desc_from_file (
 				self.fileinfo ['filepath'],
@@ -362,14 +263,15 @@ class DescriptionReader:
 			self.logger.exception ( err )
 			return self.desc_data
 
+		field_context = None
 
-		field_context = val = line = sline = None
 		for line in desc_lines:
+			field_context_ref = None
 
 			# using s(tripped)line whenever whitespace doesn't matter
 			sline = line.lstrip()
 
-			if (not sline) or (line [0] == const.DESCRIPTION_COMMENT_CHAR):
+			if (not sline) or (line [0] == config.get ( 'DESCRIPTION.comment_char' ) ):
 				# empty line or comment
 				pass
 
@@ -389,14 +291,26 @@ class DescriptionReader:
 				# line introduces a new field context, forget last one
 				field_context = None
 
-				line_components = sline.partition ( const.DESCRIPTION_FIELD_SEPARATOR )
+				line_components = sline.partition ( config.get ( 'DESCRIPTION.field_separator' ) )
 
 				if line_components [1]:
 					# line contains a field separator, set field context
-					field_context = find_field ( line_components [0] )
+					field_context_ref = self.field_definition.get ( line_components [0] )
+
+					if field_context_ref is None:
+						# useless line, skip
+						self.logger.info ( "Skipped a description field: '%s'.", line_components [0] )
+					elif field_context_ref.has_flag ( 'ignore' ):
+						# field ignored
+						self.logger.debug ( "Ignored field '%s'.", field_context )
+
+					else:
+						field_context = field_context_ref.get_name()
+
+						if not field_context:
+							raise Exception ( "Field name is not valid! This should've already been catched in DescriptionField..." )
 
-					if field_context:
-						# create a new empty list for field_context
+						# create a new empty list for this field_context
 						read_data [field_context] = []
 
 						# add values to read_data
@@ -404,9 +318,7 @@ class DescriptionReader:
 						for val in make_values ( line_components [2], field_context ):
 							read_data [field_context] . append ( val )
 
-					else:
-						# useless line, skip
-						self.logger.info ( "Skipped a description field: '%s'.", line_components [0] )
+
 
 				else:
 					# reaching this branch means that
@@ -415,11 +327,7 @@ class DescriptionReader:
 					# this should not occur in description files (bad syntax?)
 					self.logger.warning ( "Unexpected line in description file: '%s'.", line_components [0] )
 
-
-				del line_components
-
-		del sline, line, val, field_context
-
+		# -- end for --
 
 		if self._parse_read_data ( read_data ):
 			self.logger.debug ( "Successfully read file '%s' with data = %s.",
@@ -430,4 +338,4 @@ class DescriptionReader:
 		# get_desc() is preferred, but this method returns the desc data, too
 		return self.desc_data
 
-	# --- end of readfile (...) ---
+	# --- end of run (...) ---

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index 1634ef3..4493bb7 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -2,9 +2,10 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import roverlay.config
+
 class Ebuild:
-	# could move this to const
-	EBUILD_INDENT = "\t"
+	EBUILD_INDENT = roverlay.config.get ( 'EBUILD.indent', '\t' )
 
 	ADD_REMAP = {
 		# pkg vs package

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 0357e77..b6c9456 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -2,16 +2,18 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import time
 import logging
 import re
 
-from roverlay.fileio import DescriptionReader
+from roverlay.descriptionreader import DescriptionReader
 from roverlay.ebuild import Ebuild
+from roverlay import config
 
 class EbuildJob:
 	LOGGER = logging.getLogger ( 'EbuildJob' )
 
+	DEFAULT_EBUILD_HEADER = config.get ( 'EBUILD.default_header' )
+
 	# move this to const / config
 	DEPENDENCY_FIELDS = {
 		'R_SUGGESTS' : [ 'Suggests' ],
@@ -142,14 +144,7 @@ class EbuildJob:
 
 			## default ebuild header, could use some const here (eclass name,..)
 			ebuild.add ( 'ebuild_header',
-								[ 	'# Copyright 1999-' + str ( time.gmtime() [0] ) + ' Gentoo Foundation',
-									'# Distributed under the terms of the GNU General Public License v2',
-									'# $Header: $',
-									'',
-									'EAPI=4',
-									'',
-									'inherit R-packages'
-								],
+								EbuildJob.DEFAULT_EBUILD_HEADER,
 								False
 							)
 

diff --git a/roverlay/tmpconst.py b/roverlay/tmpconst.py
deleted file mode 100644
index 8519aad..0000000
--- a/roverlay/tmpconst.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# R overlay -- constants (temporary file)
-# Copyright 2006-2012 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-# matches .tgz .tbz2 .tar .tar.gz .tar.bz2
-RPACKAGE_SUFFIX_REGEX = '[.](tgz|tbz2|tar|(tar[.](gz|bz2)))'
-
-PACKAGE_CATEGORY = 'sci-R'
-
-DESCRIPTION_FIELD_SEPARATOR = ':'
-
-DESCRIPTION_COMMENT_CHAR = '#'
-
-DESCRIPTION_LIST_SPLIT_REGEX = '\s*[,;]{1}\s*'
-
-DESCRIPTION_FILE_NAME = 'DESCRIPTION'
-
-# moved to <field> -> 'allowed_values'
-##DESCRIPTION_VALID_OS_TYPES = [ "unix" ]
-
-
-# note for 2012-05-25: make this struct more organized, assign real values
-"""The map of used fields in the DESCRIPTION file
-
-	stores the real field name as well as field flags and aliases
-	that can be case-sensitive (withcase) or not (nocase)
-
-	access to these values is
-	* for aliases
-		DESCRIPTION_FIELD_MAP [<field name>] [alias] [case sensitive ? withcase : nocase] [<index>]
-
-	* for flags
-		DESCRIPTION_FIELD_MAP [<field name>] [flags] [<index>]
-
-	* default values
-		DESCRIPTION_FIELD_MAP [<field name>] [default_value]
-
-	notable flags:
-	* isList : indicates that this field has several values that are
-	           separated by commata/semicolons =:<DESCRIPTION_LIST_SPLIT_REGEX>
-	   this disables isWhitespaceList
-
-	* isWhitespaceList : indicates that this field has several values separated
-	                     by whitespace
-
-	* joinValues : indicates that the values of this field should be concatenated
-	               after reading them (with a ' ' as separator)
-	   (this implies that the read values are one string)
-
-	* mandatory : cannot proceed if a file does not contain this field (implies ignoring default values)
-
-"""
-
-DESCRIPTION_FIELD_MAP = {
-	'Description' : {
-		'flags' : [ 'joinValues' ],
-	},
-	'Title' : {
-		'flags' : [ 'joinValues' ],
-	},
-	'Package' : {
-		'flags' : [ 'joinValues' ],
-	},
-	'License' : {
-		'flags' : [ 'isList' ],
-	},
-	'Version' : {
-		'flags' : [ 'mandatory', 'joinValues' ]
-	},
-	'Suggests' : {
-		'alias' : {
-			'nocase' : [ 'Suggests', 'Suggest',
-							'%Suggests', 'Suggets', 'Recommends' ]
-		},
-	},
-	'Depends' : {
-		'alias' : {
-			'nocase' : [ 'Depends', 'Dependencies', 'Dependes',
-							'%Depends', 'Depents', 'Require', 'Requires' ],
-		},
-		'flags' : [ 'isList' ],
-		'default_value' : '',
-	},
-	'Imports' : {
-		'alias' : {
-			'nocase' : [ 'Imports', 'Import' ]
-		},
-	},
-	'LinkingTo' : {
-		'alias' : {
-			'nocase' : [ 'LinkingTo', 'LinkingdTo' ]
-		},
-	},
-	'SystemRequirements' : {
-		'alias' : {
-			'nocase' : [ 'SystemRequirements', 'SystemRequirement' ]
-		},
-	},
-	'OS_Type' : {
-		'alias' : {
-			'nocase' : [ 'OS_TYPE' ]
-		},
-		'allowed_values' : [ 'unix' ],
-	},
-	'test-default' : {
-		'default_value' : 'some default value'
-	}
-}



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

commit:     2857235f05980e0ad98351850c1422993305c6e6
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu May 31 18:22:45 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu May 31 18:22:45 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2857235f

roverlay, 2012-05-31:
	* basic logging
	** replaced some errors cases by log entries
	* started with the config module

---
 roverlay/__init__.py          |   19 ++++
 roverlay/config.py            |   60 +++++++++++++
 roverlay/descriptionfields.py |  121 ++++++++++++++++++++++++++
 roverlay/ebuild.py            |   96 +++++++++++++++------
 roverlay/ebuildjob.py         |   38 ++++++---
 roverlay/fileio.py            |  186 +++++++++++++++++++++--------------------
 6 files changed, 394 insertions(+), 126 deletions(-)

diff --git a/roverlay/__init__.py b/roverlay/__init__.py
index 863ab2b..b1557ef 100644
--- a/roverlay/__init__.py
+++ b/roverlay/__init__.py
@@ -2,4 +2,23 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import logging
+
+logging.basicConfig (
+	level=logging.DEBUG,
+	filename='roverlay.log',
+	filemode='a',
+	format='%(asctime)s %(levelname)-8s %(name)-14s -- %(message)s',
+	datefmt='%F %H:%M:%S'
+)
+
+# add console output to the logger
+ch = logging.StreamHandler()
+ch.setLevel ( logging.INFO )
+ch.setFormatter (
+	logging.Formatter  ( '%(levelname)-8s %(name)-14s -- %(message)s' )
+)
+logging.getLogger().addHandler ( ch )
+del ch
+
 VERSION = "0.0-pre1"

diff --git a/roverlay/config.py b/roverlay/config.py
new file mode 100644
index 0000000..248fc22
--- /dev/null
+++ b/roverlay/config.py
@@ -0,0 +1,60 @@
+# R overlay -- config module
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+from roverlay import descriptionfields
+
+try:
+	import configparser
+except ImportError:
+	import ConfigParser as configparser
+
+def access():
+	return ConfigTree() if ConfigTree.instance is None else ConfigTree.instance
+
+class InitialLogger:
+
+	def __init__ ( self ):
+		self.debug     = lambda x : sys.stderr.write ( "DBG  " + str ( x ) + "\n" )
+		self.info      = lambda x : sys.stderr.write ( "INFO " + str ( x ) + "\n" )
+		self.warning   = lambda x : sys.stderr.write ( "WARN " + str ( x ) + "\n" )
+		self.error     = lambda x : sys.stderr.write ( "ERR  " + str ( x ) + "\n" )
+		self.critical  = lambda x : sys.stderr.write ( "CRIT " + str ( x ) + "\n" )
+		self.exception = lambda x : sys.stderr.write ( "EXC! " + str ( x ) + "\n" )
+
+class ConfigTree:
+	# static access to the first created ConfigTree
+	instance = None
+
+	def __init__ ( self ):
+		if ConfigTree.instance is None:
+			ConfigTree.instance = self
+
+		self.logger = InitialLogger()
+
+		self.parser = dict()
+
+
+	def load_field_definition ( self, def_file, lenient=False ):
+		if not 'field_def' in self.parser:
+			self.parser ['field_def'] = configparser.SafeConfigParser ( allow_no_value=True )
+
+		try:
+			self.logger.debug ( "Reading description field definition file " + def_file + "." )
+			if lenient:
+				self.parser ['field_def'] . read ( def_file )
+			else:
+				fh = open ( def_file, 'r' )
+				self.parser ['field_def'] . readfp ( fh )
+				if fh:
+					fh.close()
+		except IOError as err:
+			self.logger.exception ( err )
+			raise
+		except configparser.MissingSectionHeaderError as mshe:
+			self.logger.exception ( mshe )
+			raise
+
+

diff --git a/roverlay/descriptionfields.py b/roverlay/descriptionfields.py
new file mode 100644
index 0000000..9c028c2
--- /dev/null
+++ b/roverlay/descriptionfields.py
@@ -0,0 +1,121 @@
+# R overlay -- description fields
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+# split from tmpconst / fileio to make configuration possible, but TODO
+
+class DescriptionField:
+
+	def __init__ ( self, name ):
+		if not name:
+			raise Exception ( "description field name is empty." )
+
+		self.name = name
+
+
+
+	def get_name ( self ):
+		return self.name
+
+	def add_flag ( self, flag, lowercase=True ):
+		if not hasattr ( self, flags ):
+			self.flags = set ()
+
+		self.flags.add ( flag, flag.lower() if lowercase else flag )
+
+		return None
+
+
+	def del_flag ( self, flag ):
+		if hasattr ( self, flags ):
+			self.flags.discard ( flag )
+		return None
+
+
+	def add_alias ( self, alias, alias_type='withcase' ):
+		if not hasattr ( self, aliases ):
+			self.aliases = dict ()
+
+		to_add = dict (
+			withcase = alias,
+			nocase   = alias.lower(),
+		) [alias_type]
+
+
+		if not alias_type in self.aliases:
+			self.aliases [alias_type] = set ()
+
+		self.aliases [alias_type] . add ( to_add )
+
+		return None
+
+
+
+	def add_simple_alias ( self, alias, withcase=True ):
+		if withcase:
+			return self.add_alias ( alias, alias_type='withcase' )
+		else:
+			return self.add_alias ( alias, alias_type='nocase' )
+
+
+
+	def get_default_value ( self ):
+		if hasattr ( self, 'default_value' ):
+			return self.default_value
+		else:
+			return None
+
+
+	def get ( self, key, fallback_value=None ):
+		if hasattr ( self, key ):
+			return self.key
+		else:
+			return fallback_value
+
+	def matches ( self, field_identifier ):
+		return bool ( self.name == field_identifier ) if field_identifier else False
+
+	def matches_alias ( self, field_identifier ):
+
+		if not field_identifier:
+			return False
+		if not hasattr ( self, aliases ):
+			return False
+
+		if 'withcase' in self.aliases:
+			if field_identifier in self.aliases ['withcase']:
+				return True
+
+		if 'nocase' in self.aliases:
+			field_id_lower = field_identifier.lower()
+			if field_id_lower in self.aliases ['nocase']:
+				return True
+
+	def has_flag ( self, flag, lowercase=True ):
+		if not hasattr ( self, flags ):
+			return False
+
+		return bool ( (flag.lower() if lowercase else flag) in self.flags )
+
+class DescriptionFields:
+
+	def __init__ ( self ):
+		fields = dict ()
+
+	def add ( self, desc_field ):
+		if desc_field:
+			if isinstance ( desc_field, DescriptionField ):
+				fields [desc_field.get_name()] = desc_field
+				return 1
+			elif isinstance ( desc_field, str ):
+				fields [desc_field] = DescriptionField ( desc_field )
+				return 2
+
+		return 0
+
+	def get ( self, field_name ):
+		return self.fields [field_name] if field_name in self.fields else None
+
+	# ... TODO
+

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index 8c960a2..1634ef3 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -6,16 +6,31 @@ class Ebuild:
 	# could move this to const
 	EBUILD_INDENT = "\t"
 
-	def __init__ ( self ):
+	ADD_REMAP = {
+		# pkg vs package
+		'package_name'     : 'pkg_name',
+		'package_version'  : 'pkg_version',
+		'package_revision' : 'pkg_revision',
+		# TITLE is in DESCRIPTION
+		'TITLE'            : 'DESCRIPTION',
+	}
+
+	def __init__ ( self, logger ):
 		"""Initializes an Ebuild.
 		This is an abstraction layer between the verified + calculated data
 		and the ebuild data, which can be written into a file / stdout / stdin.
 		Most functions here assume that everything is fine when it reaches them.
+
+		arguments:
+		* logger -- logger for this Ebuild
 		"""
 
+		self.logger = logger
+
 		# elements in ebuild_data are either a str or a list of str
 		self._data = dict ()
 		self._ebuild_lines = None
+		self._ebuild_name = None
 
 	# --- end of __init__ (...) ---
 
@@ -24,6 +39,8 @@ class Ebuild:
 		This saves some memory but makes this Ebuild read-only.
 		"""
 		if self._ebuild_lines:
+			# determine the ebuild name first
+			self._ebuild_name = self.suggest_name()
 			del self._data
 			self._data = None
 
@@ -56,12 +73,18 @@ class Ebuild:
 
 	# --- end of prepare (...) ---
 
+	def has_ebuild ( self ):
+		"""Returns True if this object has ebuild text lines else False."""
+		return bool ( self._ebuild_lines )
+	# --- end of has_ebuild (...) ---
+
 	def add ( self, key, value, append=True ):
 		"""Adds data to this Ebuild.
 
 		arguments:
 		* key -- identifier of the data (e.g. DEPEND).
-		         May be remapped here (e.g. merging 'Title' and 'Description')
+		         May be remapped (e.g. merging 'Title' and 'Description')
+		         or even refused here
 		* value --
 		* append -- whether to append values or overwrite existing ones,
 		            defaults to True.
@@ -72,17 +95,22 @@ class Ebuild:
 			# -- todo
 			raise Exception ("Ebuild data are readonly.")
 
-		if append and key in self._data:
-			if not isinstance ( self._data [key], list ):
-				self._data [key] = [ self._data [key] ]
-
-			if isinstance ( value, list ):
-				self._data [key].extend ( value )
-			else:
-				self._data [key].append ( value )
+		_key = Ebuild.ADD_REMAP [key] if key in Ebuild.ADD_REMAP else key
 
+		if _key is None:
+			self.logger.debug ( "add (%s, %s): filtered key.", key, str ( value ) )
 		else:
-			self._data [key] = value
+			if append and _key in self._data:
+				if not isinstance ( self._data [_key], list ):
+					self._data [_key] = [ self._data [_key] ]
+
+				if isinstance ( value, list ):
+					self._data [_key].extend ( value )
+				else:
+					self._data [_key].append ( value )
+
+			else:
+				self._data [_key] = value
 
 	# --- end of add (...) ---
 
@@ -99,14 +127,12 @@ class Ebuild:
 				self.show ( fh )
 				fh.close()
 				del fh
-				return True
 			except IOError as err:
-				# ? todo
+				self.logger.exception ( err )
 				raise
 
 		else:
-				# todo log this
-				raise Exception ("cannot write ebuild")
+				self.logger.warning ( "Cannot write ebuild - it's empty! (check with has_ebuild() before calling this method.)" )
 
 	# --- end of write (...) ---
 
@@ -128,20 +154,39 @@ class Ebuild:
 
 	# --- end of show (...) ---
 
-	def suggest_name ( self, fallback_name=None ):
+	def suggest_dir_name ( self ):
+		"""Suggests a direcory name for this Ebuild."""
+		return self._data ['pkg_name'] if 'pkg_name' in self._data else self.suggest_name().partition ( '-' )
+	# --- end of suggest_dir_name (...) ---
+
+	def suggest_name ( self, fallback_name='' ):
 		"""Suggests a file name for the ebuild. This is calculated using
 		pkg_name/version/revision. Returns a fallback_name if this is not
 		possible.
 
 		arguments:
-		fallback_name -- name to return if no suggestion available, defaults to None
+		fallback_name -- name to return if no suggestion available, defaults to empty string
 		"""
 
-		if 'pkg_name' in self._data and 'pkg_version' in self._data:
-			join = [ 'pkg_name' , 'pkg_version' ]
-			if 'pkg_revision' in self._data: join.append ('pkg_revision')
+		if self._ebuild_name:
+			return self._ebuild_name
+		elif (not self._data is None) and 'pkg_name' in self._data:
+			name_components = [ self._data ['pkg_name'] ]
+
+			if 'pkg_version' in self._data:
+				name_components.append ( self._data ['pkg_version'] )
+			else:
+				# default ver
+				name_components.append ( '1.0' )
+
+			if 'pkg_revision' in self._data:
+				rev = self._data ['pkg_revision']
+
+				# omit rev == 0 and invalid revisions
+				if isinstance ( rev, int ) and rev > 0:
+					name_components.append ( 'r' + rev )
 
-			return '-' . join ( [ self._data [c] for c in join ] )
+			return '-'.join ( name_components )
 
 		else:
 			return fallback_name
@@ -316,7 +361,7 @@ class Ebuild:
 			if 'SRC_URI' in self._data:
 				add_easyvar ( ebuild_lines, "SRC_URI" )
 			else:
-				# > calculate SRC_URI using self._data ['origin']
+				# > calculate SRC_URI using self._data ['origin'] -- either here or in eclass
 				ebuild_lines.append ( make_var ( "SRC_URI" , None ) )
 				# (temporary, todo) setting restrict to fetch
 				ebuild_lines.append ( make_var ( "RESTRICT" , "fetch" ) )
@@ -345,9 +390,8 @@ class Ebuild:
 			del dep_and_use
 			return remove_newlines ( ebuild_lines )
 
-		except Exception as err:
-			# log this
-			## ..
-			raise
+		except ( ValueError, KeyError, NameError ) as err:
+			self.logger.error ( "Cannot create ebuild text lines. The error message was %s.", str ( err ) )
+			return None
 
 		# --- end of make_ebuild_lines (...) ---

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 2d29643..0357e77 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -3,11 +3,15 @@
 # Distributed under the terms of the GNU General Public License v2
 
 import time
+import logging
+import re
 
 from roverlay.fileio import DescriptionReader
 from roverlay.ebuild import Ebuild
 
 class EbuildJob:
+	LOGGER = logging.getLogger ( 'EbuildJob' )
+
 	# move this to const / config
 	DEPENDENCY_FIELDS = {
 		'R_SUGGESTS' : [ 'Suggests' ],
@@ -43,10 +47,12 @@ class EbuildJob:
 		dep resolver 'communication channel', status codes etc.
 		"""
 
-		self.package_file = package_file
+		#self.package_file = package_file
 		self.dep_resolver = dep_resolver
 		# get description reader from args?
-		self.description_reader = DescriptionReader()
+		self.description_reader = DescriptionReader ( package_file )
+
+		self.logger = EbuildJob.LOGGER.getChild ( self.description_reader.get_log_name () )
 
 		self.ebuild = None
 
@@ -92,23 +98,29 @@ class EbuildJob:
 		"""
 
 		# TODO move hardcoded entries to config/const
+		# TODO metadata.xml creation
 
 		try:
 
 			# set status or return
 			if not self._set_status ( 'BUSY', True ): return
 
-			read_data = self.description_reader.readfile ( self.package_file )
-
-			if read_data is None:
-				# set status accordingly
+			desc = self.description_reader.get_desc ( True )
+			if desc is None:
 				self._set_status ( 'FAIL' )
-				return
+				self.logger.info ( 'Cannot create an ebuild for this package.' )
+
 
-			fileinfo  = read_data ['fileinfo']
-			desc      = read_data ['description_data']
+			fileinfo  = self.description_reader.get_fileinfo ()
+
+			ebuild = Ebuild ( self.logger.getChild ( "Ebuild" ) )
+
+			ebuild.add ( 'pkg_name', fileinfo ['package_name'] )
+			# TODO move regex to config/const
+			ebuild.add ( 'pkg_version',
+							re.sub ( '[-]{1,}', '.', fileinfo ['package_version'] )
+							)
 
-			ebuild = Ebuild()
 
 			have_description = False
 
@@ -216,7 +228,7 @@ class EbuildJob:
 
 		except Exception as any_exception:
 			# any exception means failure
-			self.status = 'FAIL'
+			self._set_status ( 'FAIL' )
 			raise
 
 	# --- end of run (...) ---
@@ -231,15 +243,19 @@ class EbuildJob:
 
 		if new_status == 'FAIL':
 			# always allowed
+			self.logger.info ( "Entering status '%s'.", new_status )
 			self.status = new_status
+			return True
 
 		if new_status and new_status in EbuildJob.STATUS_LIST:
 			# check if jumping from self.status to new_status is allowed
 			if new_status in EbuildJob.STATUS_BRANCHMAP [self.status]:
+				self.logger.debug ( "Entering status '%s'.", new_status )
 				self.status = new_status
 				return True
 
 		# default return
+		self.logger.error ( "Cannot enter status '%s'.", new_status )
 		return False
 
 	# --- end of _set_status (...) ---

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 7c89356..5c01527 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -3,11 +3,10 @@
 # Distributed under the terms of the GNU General Public License v2
 
 import re
-import os.path
 import tarfile
+import logging
+import os.path
 
-# temporary import until logging is implemented
-from sys import stderr as logging
 
 # temporary import until config and real constants are implemented
 from roverlay import tmpconst as const
@@ -15,12 +14,70 @@ from roverlay import tmpconst as const
 class DescriptionReader:
 	"""Description Reader"""
 
-	def __init__ ( self ):
+	LOGGER = logging.getLogger ( 'DescriptionReader' )
+
+	def __init__ ( self, package_file, read_now=False ):
 		"""Initializes a DESCRIPTION file reader."""
-		pass
+
+		self.fileinfo  = self.make_fileinfo ( package_file )
+		self.logger    = DescriptionReader.LOGGER.getChild ( self.get_log_name() )
+		self.desc_data = None
+
+
+		if read_now:
+			self.run()
 
 	# --- end of __init__ (...) ---
 
+	def get_log_name ( self ):
+		try:
+			return self.fileinfo ['filename']
+		except Exception as any_exception:
+			return '__undef__'
+
+	def get_desc ( self, run_if_unset=True ):
+		if self.desc_data is None:
+			self.run ()
+
+		return self.desc_data
+	# --- end of get_desc (...) ---
+
+	def get_fileinfo ( self ):
+		return self.fileinfo
+	# --- end of get_fileinfo (...) ---
+
+	def make_fileinfo ( self, filepath ):
+		"""Returns some info about the given filepath as dict whose contents are
+			the file path, the file name ([as package_file with suffix and]
+			as filename with tarball suffix removed), the package name
+			and the package_version.
+
+		arguments:
+		* filepath --
+		"""
+
+		package_file = os.path.basename ( filepath )
+
+		filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
+
+		# todo move that separator to const
+		package_name, sepa, package_version = filename.partition ( '_' )
+
+		if not sepa:
+			# file name unexpected, tarball extraction will (probably) fail
+			DescriptionReader.LOGGER.error ( "unexpected file name %s.'", filename )
+
+		return dict (
+			filepath        = filepath,
+			filename        = filename,
+			package_file    = package_file,
+			package_name    = package_name,
+			#package_origin = ?,
+			package_version = package_version,
+		)
+
+	# --- end of make_fileinfo (...) ---
+
 
 	def _parse_read_data ( self, read_data ):
 		"""Verifies and parses/fixes read data.
@@ -91,44 +148,31 @@ class DescriptionReader:
 
 
 		# check for fields that allow only certain values
-		unsuitable_fields = list()
+		unsuitable_fields = dict()
 
 		for field in read_data.keys():
-			# skip _fileinfo
-			if field  != '_fileinfo':
-				if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
-					if not value_in_strlist ( read_data [field],
-						const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
-					): unsuitable_fields.append ( field )
+			if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
+				if not value_in_strlist (
+							read_data [field],
+							const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
+						):
+					unsuitable_fields.append [field] = read_data [field]
 
-		valid = True
-
-		if len ( missing_fields ):
-			valid = False
-
-			logging.write (
-				"Verification of mandatory fields failed, the result leading to this was: " +
-				str ( missing_fields ) + "\n"
-			)
-
-			#<raise custom exception>
-			raise Exception ("^^^look above")
-
-		if len ( unsuitable_fields ):
-			valid = False
-
-			logging.write (
-				"Some fields have values that forbid further parsing, the result leading to this was: " +
-					str ( unsuitable_fields ) + "\n"
-				)
-
-		del missing_fields
 		del field
 
+		valid = not bool ( len ( missing_fields ) or len ( unsuitable_fields ) )
+		if not valid:
+			self.logger.info ( "Cannot use R package" ) # name?
+			if len ( missing_fields ):
+				self.logger.debug ( "The following mandatory description fields are missing: %s.", str ( missing_fields ) )
+			if len ( unsuitable_fields ):
+				self.logger.debug ( "The following fields have unsuitable values: %s.", str ( unsuitable_fields ) )
+
 		return valid
+
 	# --- end of _parse_read_data (...) ---
 
-	def readfile ( self, filepath ):
+	def run ( self ):
 		"""Reads a DESCRIPTION file and returns the read data if successful, else None.
 
 		arguments:
@@ -145,40 +189,6 @@ class DescriptionReader:
 		e.g. if OS_TYPE is not unix).
 		"""
 
-		def get_fileinfo ( filepath ):
-			"""Returns some info about the given filepath as dict whose contents are
-				the file path, the file name ([as package_file with suffix and]
-				as filename with tarball suffix removed), the package name
-				and the package_version.
-
-			arguments:
-			* filepath --
-			"""
-
-			package_file = os.path.basename ( filepath )
-
-			filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
-
-			# todo move that separator to const
-			package_name, sepa, package_version = filename.partition ( '_' )
-
-			if not sepa:
-				# file name unexpected, tarball extraction will (probably) fail
-				#raise Exception ("file name unexpected")
-				logging.write ( "unexpected file name '" + filename + "'.\n" )
-
-			return dict (
-				filepath        = filepath,
-				filename        = filename,
-				package_file    = package_file,
-				package_name    = package_name,
-				#package_origin = ?,
-				package_version = package_version,
-			)
-
-		# --- end of get_fileinfo (...) ---
-
-
 		def make_values ( value_str, field_context=None ):
 			"""Extracts relevant data from value_str and returns them as list.
 
@@ -252,7 +262,7 @@ class DescriptionReader:
 			file is read (<pkg_name>/DESCRIPTION) or a normal file.
 			"""
 
-			logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
+			self.logger.debug ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
 
 			if not ( isinstance ( filepath, str ) and filepath ):
 				raise Exception ( "bad usage" )
@@ -338,16 +348,19 @@ class DescriptionReader:
 		# --- end of find_field (...) ---
 
 
+		self.desc_data = None
 		read_data = dict ()
-		fileinfo = get_fileinfo ( filepath )
 
 
 		try:
-			desc_lines = get_desc_from_file ( filepath, fileinfo ['package_name'] )
+			desc_lines = get_desc_from_file (
+				self.fileinfo ['filepath'],
+				self.fileinfo ['package_name']
+			)
 
 		except IOError as err:
-			# <todo>
-			raise
+			self.logger.exception ( err )
+			return self.desc_data
 
 
 		field_context = val = line = sline = None
@@ -393,18 +406,15 @@ class DescriptionReader:
 
 					else:
 						# useless line, skip
-						logging.write (
-							"Skipping a line, first line component (field identifier?) was: '"
-							+ line_components [0] + "'\n"
-						)
+						self.logger.info ( "Skipped a description field: '%s'.", line_components [0] )
 
 				else:
 					# reaching this branch means that
 					#  (a) line has no leading whitespace
 					#  (b) line has no separator (:)
 					# this should not occur in description files (bad syntax?)
-					logging.write ( "***" + line_components [0] + "***\n")
-					raise Exception ( "bad file" )
+					self.logger.warning ( "Unexpected line in description file: '%s'.", line_components [0] )
+
 
 				del line_components
 
@@ -412,14 +422,12 @@ class DescriptionReader:
 
 
 		if self._parse_read_data ( read_data ):
-			#logging.write ( '## success ##\n' )
-			#logging.write ( ( str ( read_data ) ) )
-			return dict (
-				fileinfo = fileinfo,
-				description_data = read_data
-			)
-		else:
-			logging.write ( '## fail ##\n' )
-			return None
+			self.logger.debug ( "Successfully read file '%s' with data = %s.",
+										self.fileinfo ['filepath'], str ( read_data )
+									)
+			self.desc_data = read_data
+
+		# get_desc() is preferred, but this method returns the desc data, too
+		return self.desc_data
 
 	# --- end of readfile (...) ---



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

commit:     3eecf500d7f96746df2a0147150ad390ca4652dc
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 20:09:30 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 20:09:30 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=3eecf500

remove newline in header
	modified:   roverlay/ebuildjob.py

---
 roverlay/ebuildjob.py |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 13800e2..2d29643 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -131,7 +131,6 @@ class EbuildJob:
 			## default ebuild header, could use some const here (eclass name,..)
 			ebuild.add ( 'ebuild_header',
 								[ 	'# Copyright 1999-' + str ( time.gmtime() [0] ) + ' Gentoo Foundation',
-									'',
 									'# Distributed under the terms of the GNU General Public License v2',
 									'# $Header: $',
 									'',



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 19:36 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 19:36 UTC (permalink / raw
  To: gentoo-commits

commit:     1486db8558672eae1054bd7b7bbc7e69913b8666
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 19:35:08 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 19:35:08 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=1486db85

roverlay, ebuildjob: useful default ebuild header
	modified:   roverlay/ebuildjob.py

---
 roverlay/ebuildjob.py |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 2767497..13800e2 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -2,6 +2,8 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import time
+
 from roverlay.fileio import DescriptionReader
 from roverlay.ebuild import Ebuild
 
@@ -120,15 +122,23 @@ class EbuildJob:
 
 
 			# origin is todo (sync module knows the package origin)
-			ebuild.add ( 'PKG_ORIGIN', 'CRAN/BIOC/... TODO!' )
+			# could calculate SRC_URI in the eclass depending on origin
+			##ebuild.add ( 'PKG_ORIGIN', 'CRAN/BIOC/... TODO!' )
 			ebuild.add ( 'SRC_URI', 'where? TODO!' )
 
 			ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
 
+			## default ebuild header, could use some const here (eclass name,..)
 			ebuild.add ( 'ebuild_header',
-								[ '# test header, first line\n',
-									'# test header, second line\n\n\n\n',
-									'#third\n\n#fifth' ],
+								[ 	'# Copyright 1999-' + str ( time.gmtime() [0] ) + ' Gentoo Foundation',
+									'',
+									'# Distributed under the terms of the GNU General Public License v2',
+									'# $Header: $',
+									'',
+									'EAPI=4',
+									'',
+									'inherit R-packages'
+								],
 								False
 							)
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 19:36 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 19:36 UTC (permalink / raw
  To: gentoo-commits

commit:     925f11b49cd410c164c822c29ef36884e6c22b99
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 19:35:47 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 19:35:47 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=925f11b4

roverlay, ebuild: reduce lines of code by not writing unchanged vars (IUSE="${IUSE:-}" etc.)
	modified:   roverlay/ebuild.py

---
 roverlay/ebuild.py |   21 ++++++++++++++++-----
 1 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index df2d028..8c960a2 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -163,9 +163,11 @@ class Ebuild:
 			have_suggests = bool ( 'RSUGGESTS' in self._data and self._data ['RSUGGESTS'] )
 
 			# set defaults: inherit eclass + include depend in rdepend
+			# TODO: is ${DEPEND:-},... necessary?
 			ret = dict (
 				DEPEND  = [ '${DEPEND:-}' ],
-				RDEPEND = [ '${DEPEND:-}',  '${RDEPEND:-}' ],
+				# RDEPEND: assuming that the eclass includes it's DEPEND in RDEPEND
+				RDEPEND = [ '${RDEPEND:-}' ],
 				IUSE    = [ '${IUSE:-}' ],
 			)
 
@@ -305,7 +307,9 @@ class Ebuild:
 
 			add_easyvar ( ebuild_lines, "PKG_FILE" )
 			if 'PKG_ORIGIN' in self._data:
-				add_easyvar ( ebuild_lines, "PKG_ORIGIN", None, True )
+				add_easyvar ( ebuild_lines, "PKG_ORIGIN", None, False )
+
+			ebuild_lines.append ( "" )
 
 			add_easyvar ( ebuild_lines, "DESCRIPTION" )
 
@@ -323,13 +327,20 @@ class Ebuild:
 
 			dep_and_use = get_dep_and_use ()
 
-			ebuild_lines.append ( make_var ( "IUSE", dep_and_use ['IUSE'], True ) )
+			# check that IUSE has more than one element, don't write IUSE="${IUSE:-}" etc.
+			if len ( dep_and_use ['IUSE'] ) > 1:
+				ebuild_lines.append ( make_var ( "IUSE", dep_and_use ['IUSE'], True ) )
 
 			if 'R_SUGGESTS' in dep_and_use:
 				ebuild_lines.append ( make_var ( "R_SUGGESTS", dep_and_use ['R_SUGGESTS'], False ) )
 
-			ebuild_lines.append ( make_var ( "DEPEND", dep_and_use ['DEPEND'], False ) )
-			ebuild_lines.append ( make_var ( "RDEPEND", dep_and_use ['RDEPEND'], False ) )
+			# see IUSE
+			if len ( dep_and_use ['DEPEND'] ) > 1:
+				ebuild_lines.append ( make_var ( "DEPEND", dep_and_use ['DEPEND'], False ) )
+
+			# see IUSE
+			if len ( dep_and_use ['RDEPEND'] ) > 1:
+				ebuild_lines.append ( make_var ( "RDEPEND", dep_and_use ['RDEPEND'], False ) )
 
 			del dep_and_use
 			return remove_newlines ( ebuild_lines )



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

commit:     eecacfa624c9c07a6d5fab9b2867cf201599b869
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 16:07:34 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 16:07:34 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=eecacfa6

remove @classmethod decorators
	modified:   ebuild.py
	modified:   ebuildcreator.py
	modified:   ebuildjob.py

---
 roverlay/ebuild.py        |    7 -------
 roverlay/ebuildcreator.py |   15 ++++++---------
 roverlay/ebuildjob.py     |   14 ++++----------
 3 files changed, 10 insertions(+), 26 deletions(-)

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index 6316495..df2d028 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -6,7 +6,6 @@ class Ebuild:
 	# could move this to const
 	EBUILD_INDENT = "\t"
 
-	@classmethod
 	def __init__ ( self ):
 		"""Initializes an Ebuild.
 		This is an abstraction layer between the verified + calculated data
@@ -20,7 +19,6 @@ class Ebuild:
 
 	# --- end of __init__ (...) ---
 
-	@classmethod
 	def cleanup ( self ):
 		"""Removes stored data if ebuild_lines have already been calculated.
 		This saves some memory but makes this Ebuild read-only.
@@ -31,7 +29,6 @@ class Ebuild:
 
 	# --- end of cleanup (...) ---
 
-	@classmethod
 	def prepare ( self, force_update=False, cleanup_after=False ):
 		"""Tells this Ebuild to create ebuild lines.
 
@@ -59,7 +56,6 @@ class Ebuild:
 
 	# --- end of prepare (...) ---
 
-	@classmethod
 	def add ( self, key, value, append=True ):
 		"""Adds data to this Ebuild.
 
@@ -90,7 +86,6 @@ class Ebuild:
 
 	# --- end of add (...) ---
 
-	@classmethod
 	def write ( self, file_to_write ):
 		"""Writes an ebuild file.
 
@@ -115,7 +110,6 @@ class Ebuild:
 
 	# --- end of write (...) ---
 
-	@classmethod
 	def show ( self, file_handle ):
 		"""Prints the ebuild content into a file_handle.
 
@@ -154,7 +148,6 @@ class Ebuild:
 
 	# --- end of suggest_name (...) ---
 
-	@classmethod
 	def _make_ebuild_lines ( self ):
 		"""Creates text lines for this Ebuild.
 		It assumes that enough data to do this are available. Exceptions (KeyError, NameError, ...)

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index 54a1c6a..bc74490 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -6,9 +6,6 @@ from roverlay.ebuildjob import EbuildJob
 
 class EbuildCreator:
 
-
-
-	@classmethod
 	def __init__ ( self ):
 		"""Initializes an EbuildCreator. This is an Object that controls the
 		R package -> ebuild creation. It continuously creates EbuildJobs for
@@ -20,8 +17,6 @@ class EbuildCreator:
 
 	# --- end of init (...) ---
 
-
-	@classmethod
 	def add_package ( self, package_file ):
 		"""Adds an R package to the EbuildCreator, which means that an EbuildJob
 		will be created for it. Returns the EbuildJob, which is also stored
@@ -30,6 +25,7 @@ class EbuildCreator:
 		arguments:
 		* package_file -- path R package file
 		"""
+
 		new_job = EbuildJob ( package_file, self.get_resolver ( False ) )
 
 		self.ebuild_jobs.append ( new_job )
@@ -38,7 +34,6 @@ class EbuildCreator:
 
 	# --- end of add_package (...) ---
 
-	@classmethod
 	def get_resolver ( self, readonly=True ):
 		"""Returns a communication channel to the dependency resolver.
 
@@ -52,19 +47,21 @@ class EbuildCreator:
 
 	# --- end of get_resolver (...) ---
 
-	@classmethod
 	def run ( self ):
 		"""Tells all EbuildJobs to run."""
 		for job in self.ebuild_jobs:
 			job.run()
 
-	@classmethod
+	# --- end of run (...) ---
+
 	def collect_ebuilds ( self ):
 		"""Returns all ebuilds. (They may not be ready / TODO)"""
 		ebuilds = [ job.get_ebuild() for job in self.ebuild_jobs ]
 		return [ ebuild for ebuild in ebuilds if (not ebuild is None) ]
 
-	@classmethod
+	# --- end of collect_ebuilds (...) ---
+
+
 	def get_ebuild_header ( self, ebuild_header_file=None ):
 		"""Reads and returns the content of an ebuild header file.
 		This is a normal file that can be included in ebuilds.

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index d45dfdf..2767497 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -28,7 +28,6 @@ class EbuildJob:
 		FAIL         = [],
 	)
 
-	@classmethod
 	def __init__ ( self, package_file, dep_resolver=None ):
 		"""Initializes an EbuildJob, which creates an ebuild for an R package.
 
@@ -53,7 +52,6 @@ class EbuildJob:
 
 	# --- end of __init__ (...) ---
 
-	@classmethod
 	def get_ebuild ( self ):
 		"""Returns the Ebuild that is created by this object. Note that you should
 		check the status with status ( $TODO::EBUILD_READY ) before trying to use
@@ -64,7 +62,6 @@ class EbuildJob:
 
 	# --- end of get_ebuild (...) ---
 
-	@classmethod
 	def get_status ( self, expected_status=None ):
 		"""Returns the current status of this job or a bool that indicates
 		whether to current status matches the expected one.
@@ -79,7 +76,6 @@ class EbuildJob:
 
 	# --- end of get_status (...) ---
 
-	@classmethod
 	def done_success ( self ):
 		"""Returns True if this has been successfully finished."""
 		return get_status ( 'SUCCESS' )
@@ -87,7 +83,6 @@ class EbuildJob:
 	# --- end of done_success (...) ---
 
 
-	@classmethod
 	def run ( self ):
 		"""Tells this EbuildJob to run. This means that it reads the package file,
 		resolves dependencies using its resolver (TODO) and creates
@@ -125,7 +120,8 @@ class EbuildJob:
 
 
 			# origin is todo (sync module knows the package origin)
-			ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
+			ebuild.add ( 'PKG_ORIGIN', 'CRAN/BIOC/... TODO!' )
+			ebuild.add ( 'SRC_URI', 'where? TODO!' )
 
 			ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
 
@@ -206,9 +202,8 @@ class EbuildJob:
 			## finalize self.ebuild: forced text creation + make it readonly
 			if ebuild.prepare ( True, True ):
 				self.ebuild = ebuild
-				return None
-			else:
-				return None
+
+			return None
 
 		except Exception as any_exception:
 			# any exception means failure
@@ -217,7 +212,6 @@ class EbuildJob:
 
 	# --- end of run (...) ---
 
-	@classmethod
 	def _set_status ( self, new_status, ignore_invalid=False ):
 		"""Changes the status of this job. May refuse to do that if invalid change
 		requested (e.g. 'FAIL' -> 'SUCCESS').



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

commit:     0ab8e34e33388ff12025c4a05969a891a9dcb8c4
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 16:08:30 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 16:08:30 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0ab8e34e

roverlay, fileio: refactored and @classmethod decorators removed

---
 roverlay/fileio.py |  457 +++++++++++++++++++++++++---------------------------
 1 files changed, 223 insertions(+), 234 deletions(-)

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 295d904..7c89356 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -15,217 +15,13 @@ from roverlay import tmpconst as const
 class DescriptionReader:
 	"""Description Reader"""
 
-	@classmethod
 	def __init__ ( self ):
 		"""Initializes a DESCRIPTION file reader."""
 		pass
 
-	@classmethod
-	def _get_fields_with_flag ( self, flag, foce_update=False ):
+	# --- end of __init__ (...) ---
 
-		matching_fields = []
 
-		field = None
-		for field in const.DESCRIPTION_FIELD_MAP.keys():
-			if flag is None:
-				matching_fields.append ( field )
-
-			elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-				if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
-					matching_fields.append ( field )
-
-		del field
-		return matching_fields
-
-
-	@classmethod
-	def _find_field ( self , field_identifier ):
-		"""Determines the real name of a field.
-
-		arguments:
-		* field_identifier -- name of the field as it appears in the DESCRIPTION file
-
-		At first, it is checked whether field_identifier matches the name of
-		a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
-		Then, a new iteration over the field map compares field_identifier
-		with all aliases until the first case-(in)sensitive match (-> immediate return).
-		None will be returned if none of the above searches succeed.
-
-		In other words: this method decides whether a field_identifier will be used and if so,
-		with which name.
-		"""
-
-		# save some time by prevent searching if field_id is empty
-		if not field_identifier:
-			return None
-
-		# search for real field names first
-		for field in const.DESCRIPTION_FIELD_MAP.keys():
-			if field_identifier == field:
-				return field
-
-		field_id_lower = field_identifier.lower()
-
-		for field in const.DESCRIPTION_FIELD_MAP.keys():
-
-			# does extra information (-> alias(es)) for this field exist?
-			if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
-
-				if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-					for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
-						if field_identifier == alias:
-							return field
-
-				if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-					for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
-						if field_id_lower == alias.lower():
-							return field
-
-				#if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
-
-		# returning None if no valid field identifier matches
-		return None
-
-	@classmethod
-	def _make_values ( self, value_str, field_context=None ):
-		"""Extracts relevant data from value_str and returns them as list.
-
-		arguments:
-		* value_str -- string that represents the (just read) values
-		* field_context -- field name the value belongs to; optional, defaults to None
-
-		It's useful to set field_context 'cause several fields ('Depends') have
-		multiple values arranged in a list (dep0, dep1 [, depK]*).
-		"""
-
-		svalue_str = value_str.strip()
-
-		if not svalue_str:
-			# empty value(s)
-			return []
-
-		elif field_context is None:
-			# default return if no context given
-			return [ svalue_str ]
-
-		elif self._check_fieldflag ( field_context ):
-			# value str is not empty and have flags for field_context, check these
-
-			if self._check_fieldflag ( field_context, 'isList' ):
-					# split up this list (that is separated by commata and/or semicolons)
-					return re.split (const.DESCRIPTION_LIST_SPLIT_REGEX, svalue_str, 0)
-
-			elif self._check_fieldflag ( field_context, 'isWhitespaceList' ):
-					# split up this list (that is separated whitespace)
-					return re.split ( '\s+', svalue_str, 0 )
-
-
-		# default return
-		return [ svalue_str ]
-
-	@classmethod
-	def _check_fieldflag ( self, field, flag_to_check=None ):
-		"""Checks if the given field has the specified flag and returns a bool.
-
-		arguments:
-		* field -- name of the field that should be checked
-		* flag_to_check -- name of the flag to check; optional, defaults to None
-
-		This method acts as 'field has any flags?' if flag_to_check is None (its default value).
-		"""
-
-		if field in const.DESCRIPTION_FIELD_MAP:
-			if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-				if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
-					return True
-				elif flag_to_check is None:
-					# 'flags' exist, return true
-					return True
-
-		return False
-
-	@staticmethod
-	def _get_desc_from_file ( filepath, pkg_name='.' ):
-		"""Reads a file returns the description data.
-
-		arguments:
-		* filepath -- file to read (str; path to tarball or file)
-		* pkg_name -- name of the package, in tarballs the description file
-		              is located in <pkg_name>/ and thus this argument is required.
-		              Defaults to '.', set to None to disable.
-
-		All exceptions are passed to the caller (TarError, IOErr, <custom>).
-		<filepath> can either be a tarball in which case the real DESCRIPTION
-		file is read (<pkg_name>/DESCRIPTION) or a normal file.
-		"""
-
-		logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
-
-		if not ( isinstance ( filepath, str ) and filepath ):
-			raise Exception ( "bad usage" )
-
-		# read describes how to import the lines from a file (e.g. rstrip())
-		#  fh, th are file/tar handles
-		read = th = fh = None
-
-		if tarfile.is_tarfile ( filepath ):
-			# filepath is a tarball, open tar handle + file handle
-			th = tarfile.open ( filepath, 'r' )
-			if pkg_name:
-				fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
-			else:
-				fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
-
-			# have to decode the lines
-			read = lambda lines : [ line.decode().rstrip() for line in lines ]
-		else:
-			# open file handle only
-			fh = open ( filepath, 'r' )
-			read = lambda lines : [ line.rstrip() for line in lines ]
-
-		x = None
-		read_lines = read ( fh.readlines() )
-		del x, read
-
-		fh.close()
-		if not th is None: th.close()
-		del fh, th
-
-		return read_lines
-
-	@staticmethod
-	def _get_fileinfo ( filepath ):
-		"""Returns some info about the given filepath as dict whose contents are
-			the file path, the file name ([as package_file with suffix and]
-			as filename with tarball suffix removed), the package name
-			and the package_version.
-
-		arguments:
-		* filepath --
-		"""
-
-		package_file = os.path.basename ( filepath )
-
-		filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
-
-		# todo move that separator to const
-		package_name, sepa, package_version = filename.partition ( '_' )
-
-		if not sepa:
-			# file name unexpected, tarball extraction will (probably) fail
-			#raise Exception ("file name unexpected")
-			logging.write ( "unexpected file name '" + filename + "'.\n" )
-
-		return dict (
-			filepath        = filepath,
-			filename        = filename,
-			package_file    = package_file,
-			package_name    = package_name,
-			#package_origin = ?,
-			package_version = package_version,
-		)
-
-	@classmethod
 	def _parse_read_data ( self, read_data ):
 		"""Verifies and parses/fixes read data.
 
@@ -233,16 +29,25 @@ class DescriptionReader:
 		* read_data -- data from file, will be modified
 		"""
 
-		def stats ( data ):
-			"""Temporary function that prints some info about the given data."""
+		def get_fields_with_flag ( flag, foce_update=False ):
+
+			matching_fields = []
+
 			field = None
-			logging.write ( "=== this is the list of read data ===\n" )
-			for field in read_data.keys():
-				logging.write ( field + " = " + str ( read_data [field] ) + "\n" )
-			logging.write ( "=== end of list ===\n" )
+			for field in const.DESCRIPTION_FIELD_MAP.keys():
+				if flag is None:
+					matching_fields.append ( field )
+
+				elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
+					if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
+						matching_fields.append ( field )
+
 			del field
+			return matching_fields
 
-		def _value_in_strlist ( _val, _list, case_insensitive=True ):
+		# --- end of get_fields_with_flag (...) ---
+
+		def value_in_strlist ( _val, _list, case_insensitive=True ):
 			"""Returns true if value is in the given list."""
 			el = None
 			if case_insensitive:
@@ -258,9 +63,7 @@ class DescriptionReader:
 
 			del el
 			return False
-
-
-		stats ( read_data )
+		# --- end of value_in_strlist (...) ---
 
 		field = None
 
@@ -270,14 +73,14 @@ class DescriptionReader:
 				read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
 
 		# join values to a single string
-		for field in self._get_fields_with_flag ( 'joinValues' ):
+		for field in get_fields_with_flag ( 'joinValues' ):
 			if field in read_data.keys():
 				read_data [field] = ' ' . join ( read_data [field] )
 
 		# ensure that all mandatory fields are set
 		missing_fields = list()
 
-		for field in self._get_fields_with_flag ( 'mandatory' ):
+		for field in get_fields_with_flag ( 'mandatory' ):
 			if field in read_data:
 				if not len (read_data [field]):
 					missing_fields.append ( field )
@@ -294,15 +97,10 @@ class DescriptionReader:
 			# skip _fileinfo
 			if field  != '_fileinfo':
 				if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
-					if not _value_in_strlist ( read_data [field],
+					if not value_in_strlist ( read_data [field],
 						const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
 					): unsuitable_fields.append ( field )
 
-
-		stats ( read_data )
-
-
-
 		valid = True
 
 		if len ( missing_fields ):
@@ -328,8 +126,8 @@ class DescriptionReader:
 		del field
 
 		return valid
+	# --- end of _parse_read_data (...) ---
 
-	@classmethod
 	def readfile ( self, filepath ):
 		"""Reads a DESCRIPTION file and returns the read data if successful, else None.
 
@@ -347,15 +145,205 @@ class DescriptionReader:
 		e.g. if OS_TYPE is not unix).
 		"""
 
-		read_data = dict ()
-		fileinfo = DescriptionReader._get_fileinfo ( filepath )
+		def get_fileinfo ( filepath ):
+			"""Returns some info about the given filepath as dict whose contents are
+				the file path, the file name ([as package_file with suffix and]
+				as filename with tarball suffix removed), the package name
+				and the package_version.
 
+			arguments:
+			* filepath --
+			"""
 
-		try:
-			desc_lines = DescriptionReader._get_desc_from_file (
-				filepath, fileinfo ['package_name']
+			package_file = os.path.basename ( filepath )
+
+			filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
+
+			# todo move that separator to const
+			package_name, sepa, package_version = filename.partition ( '_' )
+
+			if not sepa:
+				# file name unexpected, tarball extraction will (probably) fail
+				#raise Exception ("file name unexpected")
+				logging.write ( "unexpected file name '" + filename + "'.\n" )
+
+			return dict (
+				filepath        = filepath,
+				filename        = filename,
+				package_file    = package_file,
+				package_name    = package_name,
+				#package_origin = ?,
+				package_version = package_version,
 			)
 
+		# --- end of get_fileinfo (...) ---
+
+
+		def make_values ( value_str, field_context=None ):
+			"""Extracts relevant data from value_str and returns them as list.
+
+			arguments:
+			* value_str -- string that represents the (just read) values
+			* field_context -- field name the value belongs to; optional, defaults to None
+
+			It's useful to set field_context 'cause several fields ('Depends') have
+			multiple values arranged in a list (dep0, dep1 [, depK]*).
+			"""
+
+			def check_fieldflag ( field, flag_to_check=None ):
+				"""Checks if the given field has the specified flag and returns a bool.
+
+				arguments:
+				* field -- name of the field that should be checked
+				* flag_to_check -- name of the flag to check; optional, defaults to None
+
+				This method acts as 'field has any flags?' if flag_to_check is None (its default value).
+				"""
+
+				if field in const.DESCRIPTION_FIELD_MAP:
+					if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
+						if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
+							return True
+						elif flag_to_check is None:
+							# 'flags' exist, return true
+							return True
+
+				return False
+			# --- end of check_fieldflag (...) ---
+
+			svalue_str = value_str.strip()
+
+			if not svalue_str:
+				# empty value(s)
+				return []
+
+			elif field_context is None:
+				# default return if no context given
+				return [ svalue_str ]
+
+			elif check_fieldflag ( field_context ):
+				# value str is not empty and have flags for field_context, check these
+
+				if check_fieldflag ( field_context, 'isList' ):
+						# split up this list (that is separated by commata and/or semicolons)
+						return re.split (const.DESCRIPTION_LIST_SPLIT_REGEX, svalue_str, 0)
+
+				elif check_fieldflag ( field_context, 'isWhitespaceList' ):
+						# split up this list (that is separated whitespace)
+						return re.split ( '\s+', svalue_str, 0 )
+
+
+			# default return
+			return [ svalue_str ]
+
+		# --- end of make_values (...) ---
+
+		def get_desc_from_file ( filepath, pkg_name='.' ):
+			"""Reads a file returns the description data.
+
+			arguments:
+			* filepath -- file to read (str; path to tarball or file)
+			* pkg_name -- name of the package, in tarballs the description file
+							  is located in <pkg_name>/ and thus this argument is required.
+							  Defaults to '.', set to None to disable.
+
+			All exceptions are passed to the caller (TarError, IOErr, <custom>).
+			<filepath> can either be a tarball in which case the real DESCRIPTION
+			file is read (<pkg_name>/DESCRIPTION) or a normal file.
+			"""
+
+			logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
+
+			if not ( isinstance ( filepath, str ) and filepath ):
+				raise Exception ( "bad usage" )
+
+			# read describes how to import the lines from a file (e.g. rstrip())
+			#  fh, th are file/tar handles
+			read = th = fh = None
+
+			if tarfile.is_tarfile ( filepath ):
+				# filepath is a tarball, open tar handle + file handle
+				th = tarfile.open ( filepath, 'r' )
+				if pkg_name:
+					fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
+				else:
+					fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
+
+				# have to decode the lines
+				read = lambda lines : [ line.decode().rstrip() for line in lines ]
+			else:
+				# open file handle only
+				fh = open ( filepath, 'r' )
+				read = lambda lines : [ line.rstrip() for line in lines ]
+
+			x = None
+			read_lines = read ( fh.readlines() )
+			del x, read
+
+			fh.close()
+			if not th is None: th.close()
+			del fh, th
+
+			return read_lines
+
+		# --- end of get_desc_from_file (...) ---
+
+		def find_field ( field_identifier ):
+			"""Determines the real name of a field.
+
+			arguments:
+			* field_identifier -- name of the field as it appears in the DESCRIPTION file
+
+			At first, it is checked whether field_identifier matches the name of
+			a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
+			Then, a new iteration over the field map compares field_identifier
+			with all aliases until the first case-(in)sensitive match (-> immediate return).
+			None will be returned if none of the above searches succeed.
+
+			In other words: this method decides whether a field_identifier will be used and if so,
+			with which name.
+			"""
+
+			# save some time by prevent searching if field_id is empty
+			if not field_identifier:
+				return None
+
+			# search for real field names first
+			for field in const.DESCRIPTION_FIELD_MAP.keys():
+				if field_identifier == field:
+					return field
+
+			field_id_lower = field_identifier.lower()
+
+			for field in const.DESCRIPTION_FIELD_MAP.keys():
+
+				# does extra information (-> alias(es)) for this field exist?
+				if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
+
+					if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
+						for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
+							if field_identifier == alias:
+								return field
+
+					if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
+						for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
+							if field_id_lower == alias.lower():
+								return field
+
+					#if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
+
+			# returning None if no valid field identifier matches
+			return None
+
+		# --- end of find_field (...) ---
+
+
+		read_data = dict ()
+		fileinfo = get_fileinfo ( filepath )
+
+
+		try:
+			desc_lines = get_desc_from_file ( filepath, fileinfo ['package_name'] )
 
 		except IOError as err:
 			# <todo>
@@ -378,7 +366,7 @@ class DescriptionReader:
 				if field_context:
 					# context is set => append values
 
-					for val in self._make_values ( sline, field_context ):
+					for val in make_values ( sline, field_context ):
 						read_data [field_context] . append ( val )
 				else:
 					# no valid context => ignore line
@@ -392,7 +380,7 @@ class DescriptionReader:
 
 				if line_components [1]:
 					# line contains a field separator, set field context
-					field_context = self._find_field ( line_components [0] )
+					field_context = find_field ( line_components [0] )
 
 					if field_context:
 						# create a new empty list for field_context
@@ -400,7 +388,7 @@ class DescriptionReader:
 
 						# add values to read_data
 						#  no need to check line_components [2] 'cause [1] was a true str
-						for val in self._make_values ( line_components [2], field_context ):
+						for val in make_values ( line_components [2], field_context ):
 							read_data [field_context] . append ( val )
 
 					else:
@@ -424,8 +412,8 @@ class DescriptionReader:
 
 
 		if self._parse_read_data ( read_data ):
-			logging.write ( '## success ##\n' )
-			logging.write ( ( str ( read_data ) ) )
+			#logging.write ( '## success ##\n' )
+			#logging.write ( ( str ( read_data ) ) )
 			return dict (
 				fileinfo = fileinfo,
 				description_data = read_data
@@ -434,3 +422,4 @@ class DescriptionReader:
 			logging.write ( '## fail ##\n' )
 			return None
 
+	# --- end of readfile (...) ---



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

commit:     efc87322e3016a5178feb579b468ff44d8cc0b04
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 14:54:28 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 14:54:28 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=efc87322

roverlay, ebuildjob: status code and dep resolve logic
	modified:   ebuildjob.py

---
 roverlay/ebuildjob.py |  260 ++++++++++++++++++++++++++++++++++---------------
 1 files changed, 181 insertions(+), 79 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 171150c..d45dfdf 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -6,11 +6,42 @@ from roverlay.fileio import DescriptionReader
 from roverlay.ebuild import Ebuild
 
 class EbuildJob:
-	STATUS_LIST = [ 'INIT', 'BUSY', 'WAIT', 'SUCCESS', 'FAIL' ]
-	STATUS_MAP  = dict ( ( name, code ) for code, name in enumerate ( STATUS_LIST ) )
+	# move this to const / config
+	DEPENDENCY_FIELDS = {
+		'R_SUGGESTS' : [ 'Suggests' ],
+		'DEPENDS'    : ['Depends', 'Imports' ],
+		'RDEPENDS'   : [ 'LinkingTo', 'SystemRequirements' ]
+	}
+
+	##
+
+
+	STATUS_LIST = [ 'INIT', 'BUSY', 'WAIT_RESOLVE', 'SUCCESS', 'FAIL' ]
+
+	# status 'jump' control
+	# FAIL is always allowed, S -> S has to be explicitly allowed
+	STATUS_BRANCHMAP = dict (
+		INIT         = [ 'BUSY' ],
+		BUSY         = [ 'BUSY', 'WAIT_RESOLVE', 'SUCCESS' ],
+		WAIT_RESOLVE = [ 'BUSY' ],
+		SUCCESS      = [],
+		FAIL         = [],
+	)
 
 	@classmethod
 	def __init__ ( self, package_file, dep_resolver=None ):
+		"""Initializes an EbuildJob, which creates an ebuild for an R package.
+
+		arguments:
+		* package_file -- path to the R package file
+		* dep_resolver -- dependency resolver
+		"""
+
+		"""Note:
+		it is intended to run this job as thread, that's why it has its own
+		dep resolver 'communication channel', status codes etc.
+		"""
+
 		self.package_file = package_file
 		self.dep_resolver = dep_resolver
 		# get description reader from args?
@@ -18,44 +49,10 @@ class EbuildJob:
 
 		self.ebuild = None
 
-		self._status = 0 # todo
+		self.status = 'INIT'
 
 	# --- end of __init__ (...) ---
 
-	@staticmethod
-	def get_statuscode ( status_id ):
-		if status_id == 'ALL':
-			return EbuildJob.STATUS_LIST
-		elif isinstance ( status_id, int ):
-			if status_id > 0 and status_id < len ( STATUS_LIST ):
-				return EbuildJob.STATUS_LIST [status_id]
-		elif status_id in EbuildJob.STATUS_MAP:
-			return EbuildJob.STATUS_MAP [status_id]
-
-		return None
-
-	# --- end of get_statuscode (...) ---
-
-	@classmethod
-	def status ( self, expected_status=None ):
-		"""Returns the current status of this job or a bool that indicates
-		whether to current status matches the expected one.
-
-		arguments:
-		* expected_status -- if not None: check if this job's state is expected_status
-		"""
-		if expected_status:
-			if isinstance ( expected_status, int ):
-				return bool ( self._status == expected_status )
-			elif expected_status in EbuildJob.STATUS_MAP:
-				return bool ( self._status == EbuildJob.STATUS_MAP [expected_status] )
-			else:
-				return False
-
-		return self._status
-
-		# --- end of status (...) ---
-
 	@classmethod
 	def get_ebuild ( self ):
 		"""Returns the Ebuild that is created by this object. Note that you should
@@ -68,73 +65,178 @@ class EbuildJob:
 	# --- end of get_ebuild (...) ---
 
 	@classmethod
-	def _set_status ( self, new_status ):
-		self._status = EbuildJob.get_statuscode ( new_status )
-		return True
+	def get_status ( self, expected_status=None ):
+		"""Returns the current status of this job or a bool that indicates
+		whether to current status matches the expected one.
 
-	# --- end of _set_status (...) ---
+		arguments:
+		* expected_status -- if not None: check if this job's state is expected_status
+		"""
+		if not expected_status is None:
+			return bool ( self.status == expected_status )
+		else:
+			return self.status
+
+	# --- end of get_status (...) ---
+
+	@classmethod
+	def done_success ( self ):
+		"""Returns True if this has been successfully finished."""
+		return get_status ( 'SUCCESS' )
+
+	# --- end of done_success (...) ---
 
 
 	@classmethod
 	def run ( self ):
 		"""Tells this EbuildJob to run. This means that it reads the package file,
-		resolves dependencies (TODO) and creates an Ebuild object that is ready
-		to be written into a file.
+		resolves dependencies using its resolver (TODO) and creates
+		an Ebuild object that is ready to be written into a file.
 		"""
 
-		# check status
-		if not self.status ( 'INIT' ):
-			return
+		# TODO move hardcoded entries to config/const
 
-		if not self._set_status ( 'BUSY' ):
-			return False
+		try:
 
-		read_data = self.description_reader.readfile ( self.package_file )
+			# set status or return
+			if not self._set_status ( 'BUSY', True ): return
 
-		if read_data is None:
-			# set status accordingly
-			self._set_status ( 'FAIL' )
-			return False
+			read_data = self.description_reader.readfile ( self.package_file )
 
-		fileinfo  = read_data ['fileinfo']
-		desc      = read_data ['description_data']
+			if read_data is None:
+				# set status accordingly
+				self._set_status ( 'FAIL' )
+				return
 
-		ebuild = Ebuild()
+			fileinfo  = read_data ['fileinfo']
+			desc      = read_data ['description_data']
 
-		have_description = False
+			ebuild = Ebuild()
 
-		print ( str ( desc ) )
+			have_description = False
 
-		if 'Title' in desc:
-			have_description = True
-			ebuild.add ( 'DESCRIPTION', desc ['Title'] )
+			if 'Title' in desc:
+				ebuild.add ( 'DESCRIPTION', desc ['Title'] )
+				have_description = True
 
-		if 'Description' in desc:
-			have_description = True
-			ebuild.add ( 'DESCRIPTION', ( '// ' if have_description else '' ) + desc ['Description'] )
+			if 'Description' in desc:
+				ebuild.add ( 'DESCRIPTION', ( '// ' if have_description else '' ) + desc ['Description'] )
+				#have_description=True
 
-		if not have_description:
-			ebuild.add ( 'DESCRIPTION', '<none>' )
-		del have_description
 
-		# origin is todo (sync module knows the package origin)
-		ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
+			# origin is todo (sync module knows the package origin)
+			ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
 
-		ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
+			ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
 
-		ebuild.add ( 'ebuild_header', [ '# test header' ], False )
+			ebuild.add ( 'ebuild_header',
+								[ '# test header, first line\n',
+									'# test header, second line\n\n\n\n',
+									'#third\n\n#fifth' ],
+								False
+							)
 
-		##  have to resolve deps here
+			if self.dep_resolver and self.dep_resolver.enabled():
 
-		# enter status that allows transferring ebuild -> self.ebuild
-		if self._set_status ( 'WAIT' ):
-			# finalize self.ebuild: forced text creation + make it readonly
+				# collect depdencies from desc and add them to the resolver
+				raw_depends = dict ()
+
+				dep_type = field = None
+
+				for dep_type in EbuildJob.DEPENDENCY_FIELDS.keys():
+
+					raw_depends [dep_type] = []
+
+					for field in EbuildJob.DEPENDENCY_FIELDS [dep_type]:
+
+						if field in desc:
+							if isinstance ( desc [field], list ):
+								raw_depends.extend ( desc [field] )
+								self.dep_resolver.add_dependencies ( desc [field] )
+
+							else:
+								raw_depends.append ( desc [field] )
+								self.dep_resolver.add_depency ( desc [field] )
+
+				del field, dep_type
+
+
+				while not self.dep_resolver.done():
+
+					if not self._set_status ( 'WAIT_RESOLVE' ): return
+
+					# tell the resolver to run (again)
+					self.dep_resolver.run()
+
+					if not self._set_status ( 'BUSY' ): return
+
+				if self.dep_resolver.satisfy_request():
+
+					dep_type = dep_str = dep = None
+
+					# dependencies resolved, add them to the ebuild
+					for dep_type in raw_depends.keys():
+
+						for dep_str in raw_depends [dep_type]:
+							# lookup (str) should return a str here
+							dep = self.dep_resolver.lookup ( dep_str )
+							if dep is None:
+								raise Exception (
+									"dep_resolver is broken: lookup() returns None but satisfy_request() says ok."
+								)
+							else:
+								# add depencies in append mode
+								dep = self.dep_resolver.lookup ( dep_str )
+								ebuild.add ( dep_type,
+													self.dep_resolver.lookup ( dep_str ),
+													True
+												)
+
+					del dep, dep_str, dep_type
+
+					# tell the dep resolver that we're done here
+					self.dep_resolver.close()
+
+				else:
+					# ebuild is not creatable, set status to FAIL and close dep resolver
+					self._set_status ( 'FAIL' )
+					self.dep_resolver.close()
+					return
+
+			## finalize self.ebuild: forced text creation + make it readonly
 			if ebuild.prepare ( True, True ):
 				self.ebuild = ebuild
-				return self._set_status ( 'SUCCESS' )
-
-		self._set_status ( 'FAIL' )
-		return False
+				return None
+			else:
+				return None
 
+		except Exception as any_exception:
+			# any exception means failure
+			self.status = 'FAIL'
+			raise
 
 	# --- end of run (...) ---
+
+	@classmethod
+	def _set_status ( self, new_status, ignore_invalid=False ):
+		"""Changes the status of this job. May refuse to do that if invalid change
+		requested (e.g. 'FAIL' -> 'SUCCESS').
+
+		arguments:
+		new_status --
+		"""
+
+		if new_status == 'FAIL':
+			# always allowed
+			self.status = new_status
+
+		if new_status and new_status in EbuildJob.STATUS_LIST:
+			# check if jumping from self.status to new_status is allowed
+			if new_status in EbuildJob.STATUS_BRANCHMAP [self.status]:
+				self.status = new_status
+				return True
+
+		# default return
+		return False
+
+	# --- end of _set_status (...) ---



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

commit:     aa515930aca5c5b231bd2b00471183fc3deabf76
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 14:53:53 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 14:53:53 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=aa515930

"its" not "it's" :)
	modified:   ebuild.py
	modified:   ebuildcreator.py
	modified:   fileio.py

---
 roverlay/ebuild.py        |    2 +-
 roverlay/ebuildcreator.py |    2 +-
 roverlay/fileio.py        |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index 88dbde6..6316495 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -212,7 +212,7 @@ class Ebuild:
 			* varname -- name of the variable
 			* value -- value of the variable. This has to be either None (the default),
 			           str, or list of str.
-			* oneline_list -- if value is a list: controls whether it's components should be
+			* oneline_list -- if value is a list: controls whether its components should be
 			                  put into one line (True) or multiple (False). Defaults to True.
 			* indent_list -- if value is a list and not oneline_list:
 			                 controls whether each value line should be indentend

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index f6935a8..54a1c6a 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -68,7 +68,7 @@ class EbuildCreator:
 	def get_ebuild_header ( self, ebuild_header_file=None ):
 		"""Reads and returns the content of an ebuild header file.
 		This is a normal file that can be included in ebuilds.
-		Every header file will only be read on first access, it's content will
+		Every header file will only be read on first access, its content will
 		be stored in a dict that is shared among all EbuildCreator instances.
 
 		arguments:

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 41aad23..295d904 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -131,7 +131,7 @@ class DescriptionReader:
 		* field -- name of the field that should be checked
 		* flag_to_check -- name of the flag to check; optional, defaults to None
 
-		This method acts as 'field has any flags?' if flag_to_check is None (it's default value).
+		This method acts as 'field has any flags?' if flag_to_check is None (its default value).
 		"""
 
 		if field in const.DESCRIPTION_FIELD_MAP:



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 10:58 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 10:58 UTC (permalink / raw
  To: gentoo-commits

commit:     d42aeffc50fdee5f835b06910f0792ba079e4ddc
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 10:56:32 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 10:58:23 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d42aeffc

roverlay, ebuildjob: fix imports, run () creates an ebuild now

---
 roverlay/ebuildjob.py |  105 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 90 insertions(+), 15 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
index 0861b22..171150c 100644
--- a/roverlay/ebuildjob.py
+++ b/roverlay/ebuildjob.py
@@ -2,11 +2,12 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-from roverlay import ebuildcreator.EbuildCreator
-from roverlay import fileio.DescriptionReader
-from roverlay import ebuild.Ebuild
+from roverlay.fileio import DescriptionReader
+from roverlay.ebuild import Ebuild
 
 class EbuildJob:
+	STATUS_LIST = [ 'INIT', 'BUSY', 'WAIT', 'SUCCESS', 'FAIL' ]
+	STATUS_MAP  = dict ( ( name, code ) for code, name in enumerate ( STATUS_LIST ) )
 
 	@classmethod
 	def __init__ ( self, package_file, dep_resolver=None ):
@@ -14,10 +15,26 @@ class EbuildJob:
 		self.dep_resolver = dep_resolver
 		# get description reader from args?
 		self.description_reader = DescriptionReader()
-		self.ebuild = Ebuild()
 
-		self.status = 0 # todo
+		self.ebuild = None
 
+		self._status = 0 # todo
+
+	# --- end of __init__ (...) ---
+
+	@staticmethod
+	def get_statuscode ( status_id ):
+		if status_id == 'ALL':
+			return EbuildJob.STATUS_LIST
+		elif isinstance ( status_id, int ):
+			if status_id > 0 and status_id < len ( STATUS_LIST ):
+				return EbuildJob.STATUS_LIST [status_id]
+		elif status_id in EbuildJob.STATUS_MAP:
+			return EbuildJob.STATUS_MAP [status_id]
+
+		return None
+
+	# --- end of get_statuscode (...) ---
 
 	@classmethod
 	def status ( self, expected_status=None ):
@@ -28,18 +45,35 @@ class EbuildJob:
 		* expected_status -- if not None: check if this job's state is expected_status
 		"""
 		if expected_status:
-			return self.status
-		else:
-			return bool ( self.status == expected_status )
+			if isinstance ( expected_status, int ):
+				return bool ( self._status == expected_status )
+			elif expected_status in EbuildJob.STATUS_MAP:
+				return bool ( self._status == EbuildJob.STATUS_MAP [expected_status] )
+			else:
+				return False
+
+		return self._status
+
+		# --- end of status (...) ---
 
 	@classmethod
 	def get_ebuild ( self ):
 		"""Returns the Ebuild that is created by this object. Note that you should
 		check the status with status ( $TODO::EBUILD_READY ) before trying to use
 		the Ebuild.
+		##fixme: it is guaranteed that self.ebuild is None unless the Ebuild is successfully created##
 		"""
 		return self.ebuild
 
+	# --- end of get_ebuild (...) ---
+
+	@classmethod
+	def _set_status ( self, new_status ):
+		self._status = EbuildJob.get_statuscode ( new_status )
+		return True
+
+	# --- end of _set_status (...) ---
+
 
 	@classmethod
 	def run ( self ):
@@ -49,17 +83,58 @@ class EbuildJob:
 		"""
 
 		# check status
-		##
+		if not self.status ( 'INIT' ):
+			return
+
+		if not self._set_status ( 'BUSY' ):
+			return False
 
 		read_data = self.description_reader.readfile ( self.package_file )
 
-		if read_data is None
+		if read_data is None:
 			# set status accordingly
-			return None
+			self._set_status ( 'FAIL' )
+			return False
 
-		# transfer data from read_data to self.ebuild
-		#  have to resolve deps here
-		# <TODO>
+		fileinfo  = read_data ['fileinfo']
+		desc      = read_data ['description_data']
+
+		ebuild = Ebuild()
+
+		have_description = False
+
+		print ( str ( desc ) )
+
+		if 'Title' in desc:
+			have_description = True
+			ebuild.add ( 'DESCRIPTION', desc ['Title'] )
+
+		if 'Description' in desc:
+			have_description = True
+			ebuild.add ( 'DESCRIPTION', ( '// ' if have_description else '' ) + desc ['Description'] )
+
+		if not have_description:
+			ebuild.add ( 'DESCRIPTION', '<none>' )
+		del have_description
+
+		# origin is todo (sync module knows the package origin)
+		ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
+
+		ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
+
+		ebuild.add ( 'ebuild_header', [ '# test header' ], False )
+
+		##  have to resolve deps here
+
+		# enter status that allows transferring ebuild -> self.ebuild
+		if self._set_status ( 'WAIT' ):
+			# finalize self.ebuild: forced text creation + make it readonly
+			if ebuild.prepare ( True, True ):
+				self.ebuild = ebuild
+				return self._set_status ( 'SUCCESS' )
+
+		self._set_status ( 'FAIL' )
+		return False
 
-		return None
 
+	# --- end of run (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 10:58 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 10:58 UTC (permalink / raw
  To: gentoo-commits

commit:     a432eb5c70a8d3108faa40a4725f6b2d531fc881
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 10:55:50 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 10:58:23 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a432eb5c

roverlay, ebuildcreator: fix imports, collect_ebuilds() returns only not None ebuilds now

---
 roverlay/ebuildcreator.py |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index f439c71..f6935a8 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -2,8 +2,7 @@
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-from roverlay import ebuildjob.EbuildJob
-
+from roverlay.ebuildjob import EbuildJob
 
 class EbuildCreator:
 
@@ -62,7 +61,8 @@ class EbuildCreator:
 	@classmethod
 	def collect_ebuilds ( self ):
 		"""Returns all ebuilds. (They may not be ready / TODO)"""
-		return [ job.get_ebuild() for job in self.ebuild_jobs ]
+		ebuilds = [ job.get_ebuild() for job in self.ebuild_jobs ]
+		return [ ebuild for ebuild in ebuilds if (not ebuild is None) ]
 
 	@classmethod
 	def get_ebuild_header ( self, ebuild_header_file=None ):



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 10:58 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 10:58 UTC (permalink / raw
  To: gentoo-commits

commit:     c2cba20189488dbf0b0419dddb94176963e054e3
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 10:54:31 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 10:54:31 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=c2cba201

roverlay, ebuild: fix list.append() / list.extend()
	modified:   ebuild.py

---
 roverlay/ebuild.py |   26 ++++++++++++++++++++------
 1 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
index 495b189..88dbde6 100644
--- a/roverlay/ebuild.py
+++ b/roverlay/ebuild.py
@@ -77,10 +77,13 @@ class Ebuild:
 			raise Exception ("Ebuild data are readonly.")
 
 		if append and key in self._data:
-			if isinstance ( self._data [key], list ):
+			if not isinstance ( self._data [key], list ):
+				self._data [key] = [ self._data [key] ]
+
+			if isinstance ( value, list ):
 				self._data [key].extend ( value )
 			else:
-				self._data [key] = [ self._data [key] ].extend ( value )
+				self._data [key].append ( value )
 
 		else:
 			self._data [key] = value
@@ -173,11 +176,22 @@ class Ebuild:
 				IUSE    = [ '${IUSE:-}' ],
 			)
 
+			tmp = None
+
 			if 'DEPEND' in self._data:
-				ret ['DEPEND'].extend ( self._data ['DEPEND'] )
+				# todo: search if there is a extend method that does not split string into chars
+				tmp = self._data ['DEPEND']
+				if isinstance ( tmp, list ):
+					ret ['DEPEND'].extend ( tmp )
+				else:
+					ret ['DEPEND'].append ( tmp )
 
 			if 'RDEPEND' in self._data:
-				ret ['RDEPEND'].extend ( self._data ['RDEPEND'] )
+				tmp = self._data ['RDEPEND']
+				if isinstance ( tmp, list ):
+					ret ['RDEPEND'].extend ( tmp )
+				else:
+					ret ['RDEPEND'].append ( tmp )
 
 			if have_suggests:
 				ret ['R_SUGGESTS'] = self._data ['R_SUGGESTS']
@@ -217,14 +231,14 @@ class Ebuild:
 				if oneline_list:
 					var_value = ' '.join ( value )
 				elif indent_list:
-					var_value = ('\n' + (indent_level + 1) * EBUILD_INDENT).join ( value )
+					var_value = ('\n' + (indent_level + 1) * Ebuild.EBUILD_INDENT).join ( value )
 				else:
 					'\n'.join ( value )
 
 			else:
 				var_value = str ( value )
 
-			return indent_level * EBUILD_INDENT + varname + '"' + value_str + '"'
+			return indent_level * Ebuild.EBUILD_INDENT + varname + '="' + var_value + '"'
 
 		# --- end of make_var (...) ---
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-30 10:58 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-30 10:58 UTC (permalink / raw
  To: gentoo-commits

commit:     46138bd3fb3e24a9144bf93355cc47b9fe222d92
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed May 30 10:55:03 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed May 30 10:58:13 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=46138bd3

roverlay, fileio: include package_file in file info
	modified:   fileio.py

---
 roverlay/fileio.py |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 5d13cf8..41aad23 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -219,8 +219,9 @@ class DescriptionReader:
 		return dict (
 			filepath        = filepath,
 			filename        = filename,
-			#package_file    = package_file,
+			package_file    = package_file,
 			package_name    = package_name,
+			#package_origin = ?,
 			package_version = package_version,
 		)
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-29 17:09 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-29 17:09 UTC (permalink / raw
  To: gentoo-commits

commit:     583cc5d1d5d4c98754cde003d70a22bfe0a07f79
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue May 29 17:08:22 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue May 29 17:08:22 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=583cc5d1

roverlay, ebuildjob: module that reads a package file and creates an ebuild for it
	new file:   ebuildjob.py

---
 roverlay/ebuildjob.py |   65 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
new file mode 100644
index 0000000..0861b22
--- /dev/null
+++ b/roverlay/ebuildjob.py
@@ -0,0 +1,65 @@
+# R Overlay -- ebuild creation, "job" module
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from roverlay import ebuildcreator.EbuildCreator
+from roverlay import fileio.DescriptionReader
+from roverlay import ebuild.Ebuild
+
+class EbuildJob:
+
+	@classmethod
+	def __init__ ( self, package_file, dep_resolver=None ):
+		self.package_file = package_file
+		self.dep_resolver = dep_resolver
+		# get description reader from args?
+		self.description_reader = DescriptionReader()
+		self.ebuild = Ebuild()
+
+		self.status = 0 # todo
+
+
+	@classmethod
+	def status ( self, expected_status=None ):
+		"""Returns the current status of this job or a bool that indicates
+		whether to current status matches the expected one.
+
+		arguments:
+		* expected_status -- if not None: check if this job's state is expected_status
+		"""
+		if expected_status:
+			return self.status
+		else:
+			return bool ( self.status == expected_status )
+
+	@classmethod
+	def get_ebuild ( self ):
+		"""Returns the Ebuild that is created by this object. Note that you should
+		check the status with status ( $TODO::EBUILD_READY ) before trying to use
+		the Ebuild.
+		"""
+		return self.ebuild
+
+
+	@classmethod
+	def run ( self ):
+		"""Tells this EbuildJob to run. This means that it reads the package file,
+		resolves dependencies (TODO) and creates an Ebuild object that is ready
+		to be written into a file.
+		"""
+
+		# check status
+		##
+
+		read_data = self.description_reader.readfile ( self.package_file )
+
+		if read_data is None
+			# set status accordingly
+			return None
+
+		# transfer data from read_data to self.ebuild
+		#  have to resolve deps here
+		# <TODO>
+
+		return None
+



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-29 17:09 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-29 17:09 UTC (permalink / raw
  To: gentoo-commits

commit:     2e76c1e480434d43b6be4ade11d6ebd7a7025718
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue May 29 17:06:35 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue May 29 17:06:35 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2e76c1e4

roverlay, ebuildcreator: module that accepts package_files, schedules their processing into jobs and returns ebuilds (but is todo)
	modified:   ebuildcreator.py

---
 roverlay/ebuildcreator.py |  356 +++++++--------------------------------------
 1 files changed, 54 insertions(+), 302 deletions(-)

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index fa648b8..f439c71 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -1,350 +1,102 @@
-# R Overlay -- ebuild creation
+# R Overlay -- ebuild creation, "master" module
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-# temporary import until logging is implemented
-from sys import stderr as logging
+from roverlay import ebuildjob.EbuildJob
 
-# temporary import until config and real constants are implemented
-from roverlay import tmpconst as const
 
-from roverlay.fileio import DescriptionReader
-
-# misc TODO notes:
-# * could use caching via decorators instead of wrappers (-> later)
-# * instead of including the ebuild header in every ebuild 'export' data:
-# ** link that header
-# ** ebuild_export = [ <header_link>, str, [,str]* ]
-#
+class EbuildCreator:
 
-class Ebuild:
-	# could move this to const
-	EBUILD_INDENT = "\t"
 
-	# reading every ebuild header file (copyright, inherit <eclass>) once at most
-	#  <ebuild header file> => [<content of this file>]
-	#  shared among all ebuilds
-	ebuild_headers = dict()
 
 	@classmethod
 	def __init__ ( self ):
-		"""Initializes an empty Ebuild. This is an object that can be used to
-		create text lines for an ebuild file."""
-
-		#self.name        = ''
-		#self.version     = ''
-		#self.origin      = ''
-		#self.pkg_file    = ''
-		#self.depend      = ''
-		#self.rdepend     = ''
-		#self.rsuggests   = ''
-		#self.description = ''
+		"""Initializes an EbuildCreator. This is an Object that controls the
+		R package -> ebuild creation. It continuously creates EbuildJobs for
+		every R package added.
+		"""
+		self.ebuild_headers = dict ()
+		self.depresolve_main = None # TODO
+		self.ebuild_jobs = []
 
-		# temporary var
-		#self.TODO = ''
+	# --- end of init (...) ---
 
-		# this will be a list of str when exported data have been calculated
-		self._ebuild_export = None
 
 	@classmethod
-	def get_ebuild ( self, description_data, force_update=False ):
-		"""
-		Wrapper function that returns ebuild 'export' data.
-		This is a list of str that has no newline chars at the end of each str.
+	def add_package ( self, package_file ):
+		"""Adds an R package to the EbuildCreator, which means that an EbuildJob
+		will be created for it. Returns the EbuildJob, which is also stored
+		in the job queue.
 
 		arguments:
-		* force_update -- force calculation of export data
-
+		* package_file -- path R package file
 		"""
-		if force_update or (self._ebuild_export is None):
-			self._ebuild_export = self._make_export ( description_data )
+		new_job = EbuildJob ( package_file, self.get_resolver ( False ) )
 
-		return self._ebuild_export
+		self.ebuild_jobs.append ( new_job )
 
-	@classmethod
-	def suggest_filename ( self ):
-		"""Suggests a file name for the ebuild.
-		Calculated using ebuild data, but TODO
-		"""
-		# name-version
-		return None
+		return new_job
+
+	# --- end of add_package (...) ---
 
 	@classmethod
-	def write_ebuild ( self, file_to_write, force_update=False ):
-		"""Writes this ebuild into a file
+	def get_resolver ( self, readonly=True ):
+		"""Returns a communication channel to the dependency resolver.
 
 		arguments:
-		* file_to_write -- path of the file to write (will be overwritten if existent)
-		* force_update -- force calculation of ebuild data, don't use cached results
-
-		**TODO notes : mkdir -p $(dirname)
+		readonly -- whether the channel is listen-only (no write methods) or not
+		            defaults to True
 		"""
-		try:
-			# try to get the ebuild lines before opening the file
-			line  = None
-			# append newline here or add in _make_export()
-			lines = [ line + "\n" for line in self.get_ebuild ( force_update ) ]
-			del line
-
-			fh = open ( file_to_write, 'w' )
-			fh.writelines ( lines )
-			fh.close ()
-
-			del lines, fh
-			return True
-		except IOError as err:
-			raise
-
-		# catch failure
-		return False
-
-		@classmethod
-		def _make_ebuild_lines ( self, ebuild_content ):
-			ebuild_export = []
-			last_line_empty = False
-			line = None
-
-			# remove repeated newlines ('repoman sez: ...')
-			for line in ebuild_content:
-				line = line.rstrip()
-				if line:
-					last_line_empty = False
-				elif not last_line_empty:
-					last_line_empty = True
-				else:
-					continue
-
-				ebuild_export.append ( line )
+		# <TODO>
+		return None
+		#return self.depresolve_main.get_channel()
 
-			del last_line_empty, line
-			return ebuild_content
+	# --- end of get_resolver (...) ---
 
+	@classmethod
+	def run ( self ):
+		"""Tells all EbuildJobs to run."""
+		for job in self.ebuild_jobs:
+			job.run()
 
+	@classmethod
+	def collect_ebuilds ( self ):
+		"""Returns all ebuilds. (They may not be ready / TODO)"""
+		return [ job.get_ebuild() for job in self.ebuild_jobs ]
 
-	@staticmethod
-	def _get_ebuild_header ( ebuild_header_file=None ):
+	@classmethod
+	def get_ebuild_header ( self, ebuild_header_file=None ):
 		"""Reads and returns the content of an ebuild header file.
 		This is a normal file that can be included in ebuilds.
 		Every header file will only be read on first access, it's content will
-		be stored in a dict that is shared among all Ebuild instances.
+		be stored in a dict that is shared among all EbuildCreator instances.
 
 		arguments:
-		ebuild_header_file -- path to the header file; defaults to none which
-		                      means that nothing will be read and an empty list
-		                      is returned
+		* ebuild_header_file -- path to the header file; defaults to none which
+		                        means that nothing will be read and an empty list
+		                        is returned.
 		"""
+
 		if ebuild_header_file is None:
 			# nothing to read
 			return []
 
-		elif (ebuild_header_file in ebuild_headers):
+		elif ebuild_header_file in self.ebuild_headers:
 			# previously read
-			return ebuild_headers [ebuild_header_file]
+			return self.ebuild_headers [ebuild_header_file]
 
 		else:
-			# do read
+			# read file
 			try:
-				fh = open (ebuild_header_file, 'rU')
+				fh = open ( ebuild_header_file, 'r' )
 				lines = fh.readlines()
 				fh.close()
-				ebuild_headers [ebuild_header_file] = lines
-				del lines, fh
-				return ebuild_headers [ebuild_header_file]
+				self.ebuild_headers [ebuild_header_file] = lines
+				del fh
+				return lines
 
 			except IOError as err:
+				# todo
 				raise
 
-	@staticmethod
-	def _make_var ( varname, value=None, indent_level=0 ):
-		"""Returns a variable definitions that can be used in ebuilds, optionally
-		with indention.
-
-		arguments:
-		* varname -- name of the variable (e.g. DEPEND)
-		* value -- value of the variable; an empty var (DEPEND="") will be returned
-		           if unset (the default)
-		* indent_level -- indent var definition by indent_level levels
-		"""
-
-		if value:
-			return indent_level * EBUILD_INDENT + varname + '"' + value + '"'
-		else:
-			# empty var
-			return indent_level * EBUILD_INDENT + varname + '""'
-
-	@classmethod
-	def _make_export ( self, description_data, ebuild_header=None ):
-		"""Creates ebuild data that can be written into stdout or a file
-
-		arguments:
-		ebuild_header_file -- path to the header file; defaults to none which
-		                      means that nothing will be read and an empty list
-		                      is returned
-		"""
-
-		# this method is todo
-
-		if not isinstance (description_data, dict):
-			#todo
-			raise Exception ( "bad description data" )
-
-		errors = dict()
-
-		ebuild_content = Ebuild._get_ebuild_header ( ebuild_header )
-
-		# repeated and leading empty lines will be removed later
-		ebuild_content.append ( "" )
-
-		# the code below this line does not work
-		return
-		#raise Exception ( "under construction ..." )
-
-		if self.pkg_file:
-			ebuild_content.append ( _make_var ( "PKG_FILE" , self.pkg_file ) )
-		else:
-			# absense of a pkg source file is an error
-			errors ['PKG_FILE'] = "missing"
-
-		if self.origin:
-			ebuild_content.append ( _make_var ( "PKG_ORIGIN", self.origin ) )
-		else:
-			errors ['PKG_ORIGIN'] = "missing"
-
-		ebuild_content.append ( "" )
-
-		if self.description:
-			ebuild_content.append ( _make_var ( "DESCRIPTION", self.TODO ) )
-		else:
-			ebuild_content.append ( _make_var ( "DESCRIPTION", "<none>" ) )
-			#errors ['DESCRIPTION'] = "missing"
-
-		# determine SRC_URI (origin + pkg_file)
-		if self.pkg_file and self.origin and False:
-			# SRC_URI ~= <> + origin + pkg_file
-			ebuild_content.append ( _make_var ( "SRC_URI", "" ) )
-		else:
-			# either RESTRICT+=" fetch" or treat missing SRC_URI as critical
-			errors ['SRC_URI'] = "missing"
-
-		ebuild_content.append ( "" )
-
-		#LICENSE (!!)
-
-		rdepend = '${DEPEND:-} ' + self.rdepend
-
-		# inherit IUSE from eclass
-		iuse = '${IUSE:-}'
-
-		if self.rsuggests:
-			iuse    += ' R_suggests'
-			rdepend += ' R_suggests ? ${R_SUGGESTS}'
-			ebuild_content.append ( _make_var ( "R_SUGGESTS", self.rsuggests ) )
-
-		ebuild_content.append ( _make_var ( "IUSE", iuse ) )
-		ebuild_content.append ( "" )
-
-		# DEPEND="${DEPEND:-} <pkg dependencies>" to inherit deps from eclass
-		ebuild_content.append ( _make_var (
-											"DEPEND", '${DEPEND:-} ' + self.depend ) )
-
-		ebuild_content.append ( _make_var ( "RDEPEND", rdepend ) )
-
-		# (!!) TODO
-		if errors:
-			raise Exception ( "^^^missing components for ebuild^^^" )
-			#return None
-
-		return self._make_ebuild_lines ( ebuild_content )
-
-class EbuildCreator:
-# could move this to Ebuild
-
-		@classmethod
-		def __init__ ( self,  description_data ):
-			""""Initializes an EbuildCreator.
-			[todo]
-			"""
-			self._description_data = description_data
-
-			self._ebuild = None
-
-		@classmethod
-		def run ( self ):
-			"""Tells this EbuildCreator to operate which produces an Ebuild object
-			that can later be shown or written into a file.
-			"""
-			#todo
-			self._ebuild = None
-
-			if self._description_data is None:
-				return False
-
-			ebuild = Ebuild()
-			dref = self._description_data
-
-			ebuild.name = dref ['Package']
-			ebuild.version = dref ['Version']
-
-			ebuild.origin = "TODO"
-			ebuild.pkg_file = "TODO"
-
-			# depend rdepend rsuggest
-			ebuild.depend  = "TODO"
-			ebuild.rdepend = "TODO"
-			ebuild.suggest = "TODO"
-
-			if 'Description' in dref:
-				ebuild.description = dref ['Description']
-			elif 'Title' in dref:
-				ebuild.description = dref ['Title']
-			else:
-				ebuild.description = "<none>"
-
-			# <dep resolution here?>
-
-			ebuild.get_ebuild ( self._description_data )
-
-			# todo
-			return None
-
-
-		@classmethod
-		def show ( self ):
-			"""Prints the ebuild to stdout/err or into log"""
-			pass
-
-		@classmethod
-		def write ( self ):
-			"""Writes the ebuild into a file"""
-			pass
-
-		@classmethod
-		def ready ( self ):
-			"""Returns true if an Ebuild has been produced, else false."""
-			return not (self._ebuild is None)
-
-
-class EbuildFactory:
-
-		@classmethod
-		def __init__ ( self ):
-			"""Initializes an ebuild factory. This continously produces EbuildCreator
-			for every get_ebuild_creator ( tarball ) call.
-			"""
-			self.desc_reader = DescriptionReader()
-
-		@classmethod
-		def get_ebuild_creator ( self, tarball ):
-			"""Creates and returns an ebuild creator that will handle
-			the data retrieved from <tarball>.
-
-			arguments:
-			* tarball -- tarball to read
-			"""
-			data = self.desc_reader.readfile ( tarball )
-			if data:
-				return EbuildCreator ( data )
-			else:
-				return None
-
-
+	# --- end of get_ebuild_header (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-29 17:09 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-29 17:09 UTC (permalink / raw
  To: gentoo-commits

commit:     a60a7f76d1a2dd2d5f4d1bb3d9766a2e803f2655
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue May 29 17:03:43 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue May 29 17:03:43 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a60a7f76

roverlay, ebuild creation: Ebuild.py
* module that produces ebuild text lines
	new file:   ebuild.py

---
 roverlay/ebuild.py |  335 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 335 insertions(+), 0 deletions(-)

diff --git a/roverlay/ebuild.py b/roverlay/ebuild.py
new file mode 100644
index 0000000..495b189
--- /dev/null
+++ b/roverlay/ebuild.py
@@ -0,0 +1,335 @@
+# R Overlay -- ebuild creation, ebuild class
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+class Ebuild:
+	# could move this to const
+	EBUILD_INDENT = "\t"
+
+	@classmethod
+	def __init__ ( self ):
+		"""Initializes an Ebuild.
+		This is an abstraction layer between the verified + calculated data
+		and the ebuild data, which can be written into a file / stdout / stdin.
+		Most functions here assume that everything is fine when it reaches them.
+		"""
+
+		# elements in ebuild_data are either a str or a list of str
+		self._data = dict ()
+		self._ebuild_lines = None
+
+	# --- end of __init__ (...) ---
+
+	@classmethod
+	def cleanup ( self ):
+		"""Removes stored data if ebuild_lines have already been calculated.
+		This saves some memory but makes this Ebuild read-only.
+		"""
+		if self._ebuild_lines:
+			del self._data
+			self._data = None
+
+	# --- end of cleanup (...) ---
+
+	@classmethod
+	def prepare ( self, force_update=False, cleanup_after=False ):
+		"""Tells this Ebuild to create ebuild lines.
+
+		arguments:
+		* force_update -- create ebuild lines if they exist; defaults to False
+								and ignored if this Ebuild has been cleaned up
+		* cleanup_after -- run cleanup() after successful creation
+
+		Returns True if ebuild_lines have been created or if they exist and
+		an update has not been enforced. Else returns False.
+		"""
+		if self._ebuild_lines and not force_update:
+			return True
+		elif self._data:
+			self._ebuild_lines = self._make_ebuild_lines()
+			if self._ebuild_lines:
+				if cleanup_after: self.cleanup()
+				return True
+		elif self._ebuild_lines:
+			# self._data is None
+			return True
+
+
+		return False
+
+	# --- end of prepare (...) ---
+
+	@classmethod
+	def add ( self, key, value, append=True ):
+		"""Adds data to this Ebuild.
+
+		arguments:
+		* key -- identifier of the data (e.g. DEPEND).
+		         May be remapped here (e.g. merging 'Title' and 'Description')
+		* value --
+		* append -- whether to append values or overwrite existing ones,
+		            defaults to True.
+
+		raises: Exception when ebuild data are readonly
+		"""
+		if self._data is None:
+			# -- todo
+			raise Exception ("Ebuild data are readonly.")
+
+		if append and key in self._data:
+			if isinstance ( self._data [key], list ):
+				self._data [key].extend ( value )
+			else:
+				self._data [key] = [ self._data [key] ].extend ( value )
+
+		else:
+			self._data [key] = value
+
+	# --- end of add (...) ---
+
+	@classmethod
+	def write ( self, file_to_write ):
+		"""Writes an ebuild file.
+
+		arguments:
+		* file_to_write -- path to the file that should be written
+		"""
+		# prepare ebuild lines and open file handle after that
+		if self.prepare ( False, False ):
+			try:
+				fh = open ( file_to_write, 'w' )
+				self.show ( fh )
+				fh.close()
+				del fh
+				return True
+			except IOError as err:
+				# ? todo
+				raise
+
+		else:
+				# todo log this
+				raise Exception ("cannot write ebuild")
+
+	# --- end of write (...) ---
+
+	@classmethod
+	def show ( self, file_handle ):
+		"""Prints the ebuild content into a file_handle.
+
+		arguments:
+		file_handle -- object that has a writelines ( list ) method, e.g. file.
+
+		Returns True if writing was successful, else False.
+		"""
+		if self.prepare ( False, False ):
+			lines = [ line + "\n" for line in self._ebuild_lines ]
+			file_handle.writelines ( lines )
+			del lines
+			return True
+		else:
+			return False
+
+	# --- end of show (...) ---
+
+	def suggest_name ( self, fallback_name=None ):
+		"""Suggests a file name for the ebuild. This is calculated using
+		pkg_name/version/revision. Returns a fallback_name if this is not
+		possible.
+
+		arguments:
+		fallback_name -- name to return if no suggestion available, defaults to None
+		"""
+
+		if 'pkg_name' in self._data and 'pkg_version' in self._data:
+			join = [ 'pkg_name' , 'pkg_version' ]
+			if 'pkg_revision' in self._data: join.append ('pkg_revision')
+
+			return '-' . join ( [ self._data [c] for c in join ] )
+
+		else:
+			return fallback_name
+
+	# --- end of suggest_name (...) ---
+
+	@classmethod
+	def _make_ebuild_lines ( self ):
+		"""Creates text lines for this Ebuild.
+		It assumes that enough data to do this are available. Exceptions (KeyError, NameError, ...)
+		are passed if that's not the case.
+		"""
+
+		def get_dep_and_use():
+			"""Creates values for the DEPEND, RDEPEND, IUSE and, if possible,
+			R_SUGGESTS variables and returns them as dict { VARNAME -> VALUE }.
+			"""
+
+			# have suggests if they're set and not empty
+			have_suggests = bool ( 'RSUGGESTS' in self._data and self._data ['RSUGGESTS'] )
+
+			# set defaults: inherit eclass + include depend in rdepend
+			ret = dict (
+				DEPEND  = [ '${DEPEND:-}' ],
+				RDEPEND = [ '${DEPEND:-}',  '${RDEPEND:-}' ],
+				IUSE    = [ '${IUSE:-}' ],
+			)
+
+			if 'DEPEND' in self._data:
+				ret ['DEPEND'].extend ( self._data ['DEPEND'] )
+
+			if 'RDEPEND' in self._data:
+				ret ['RDEPEND'].extend ( self._data ['RDEPEND'] )
+
+			if have_suggests:
+				ret ['R_SUGGESTS'] = self._data ['R_SUGGESTS']
+
+				# +R_SUGGESTS, -R_SUGGESTS?
+				ret ['IUSE'].append ( 'R_suggests' )
+				# do these braces help or confuse? TODO FIXME
+				ret ['RDEPEND'].append ( '( R_suggests ? ${R_SUGGESTS} )' )
+
+			return ret
+
+		# --- end of get_dep_and_use () ---
+
+		def make_var ( varname, value=None, oneline_list=True, indent_list=True, indent_level=0 ):
+			"""Creates a <name>=<value> statement for ebuilds.
+
+			arguments:
+			* varname -- name of the variable
+			* value -- value of the variable. This has to be either None (the default),
+			           str, or list of str.
+			* oneline_list -- if value is a list: controls whether it's components should be
+			                  put into one line (True) or multiple (False). Defaults to True.
+			* indent_list -- if value is a list and not oneline_list:
+			                 controls whether each value line should be indentend
+			                 (by indent_level + 1) or not ("by 0"). Defaults to True.
+			* indent_level -- current indentation level, defaults to 0
+
+			"""
+
+			# assumption: value is either None, scalar with str representation or list of str
+			var_value = None
+
+			if not value:
+				var_value = ""
+
+			elif isinstance ( value, list ):
+				if oneline_list:
+					var_value = ' '.join ( value )
+				elif indent_list:
+					var_value = ('\n' + (indent_level + 1) * EBUILD_INDENT).join ( value )
+				else:
+					'\n'.join ( value )
+
+			else:
+				var_value = str ( value )
+
+			return indent_level * EBUILD_INDENT + varname + '"' + value_str + '"'
+
+		# --- end of make_var (...) ---
+
+		def remove_newlines ( line_list ):
+			"""
+			Removes leading, ending and repeated empty/whitespace lines in line_list.
+
+			arguments:
+			* line_list
+			"""
+			lines = []
+			line = None
+			last_line_empty = False
+
+			for line in line_list:
+				line = line.rstrip()
+				# re.sub \n{2,} \n :: FIXME?
+
+				if line:
+					last_line_empty = False
+				elif not last_line_empty:
+					last_line_empty = True
+				else:
+					continue
+
+				lines.append ( line )
+
+			# remove last line if empty
+			##if last_line_empty: (?)
+			if len ( lines ) and not lines [-1]:
+				del lines [-1]
+
+			return lines
+
+		# --- end of remove_newlines (...) ---
+
+		def add_easyvar ( ebuild_content, varname, value_key=None, add_newline=False):
+			"""Adds a 'simple' variable to the ebuild lines. This means that it
+			can directly be taken from self._data [value_key]. This method assumes
+			that value_key exists in self._data, any exceptions (KeyError) will be passed.
+
+			arguments:
+			* ebuild_content -- list of ebuild text lines, will be modified directly,
+			                     so copy it before calling addvar if you need the original list.
+			* varname -- name of the variable. Nothing happens if this is None.
+			* value_key -- key of the value, defaults to varname if it is None
+			* add_newline -- adds a newline after the var statement, defaults to False
+
+			Returns given list (ebuild_content), which will then have been modified.
+			"""
+
+			if not varname is None:
+				if value_key is None:
+					ebuild_content.append ( make_var ( varname, self._data [varname] ) )
+				else:
+					ebuild_content.append ( make_var ( varname, self._data [value_key] ) )
+
+				if add_newline:
+					ebuild_content.append ( "" )
+
+			return ebuild_content
+
+		# --- end of add_easyvar (...) ---
+
+		try:
+			ebuild_lines = []
+
+			if 'ebuild_header' in self._data:
+				ebuild_lines = self._data ['ebuild_header']
+				ebuild_lines.append ( "" )
+
+			add_easyvar ( ebuild_lines, "PKG_FILE" )
+			if 'PKG_ORIGIN' in self._data:
+				add_easyvar ( ebuild_lines, "PKG_ORIGIN", None, True )
+
+			add_easyvar ( ebuild_lines, "DESCRIPTION" )
+
+			if 'SRC_URI' in self._data:
+				add_easyvar ( ebuild_lines, "SRC_URI" )
+			else:
+				# > calculate SRC_URI using self._data ['origin']
+				ebuild_lines.append ( make_var ( "SRC_URI" , None ) )
+				# (temporary, todo) setting restrict to fetch
+				ebuild_lines.append ( make_var ( "RESTRICT" , "fetch" ) )
+
+			ebuild_lines.append ( "" )
+
+			# LICENSE ?
+
+			dep_and_use = get_dep_and_use ()
+
+			ebuild_lines.append ( make_var ( "IUSE", dep_and_use ['IUSE'], True ) )
+
+			if 'R_SUGGESTS' in dep_and_use:
+				ebuild_lines.append ( make_var ( "R_SUGGESTS", dep_and_use ['R_SUGGESTS'], False ) )
+
+			ebuild_lines.append ( make_var ( "DEPEND", dep_and_use ['DEPEND'], False ) )
+			ebuild_lines.append ( make_var ( "RDEPEND", dep_and_use ['RDEPEND'], False ) )
+
+			del dep_and_use
+			return remove_newlines ( ebuild_lines )
+
+		except Exception as err:
+			# log this
+			## ..
+			raise
+
+		# --- end of make_ebuild_lines (...) ---



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-29 17:09 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-29 17:09 UTC (permalink / raw
  To: gentoo-commits

commit:     205a0fe164142e4b9c2328672e27f98b9b76a013
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue May 29 17:03:10 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue May 29 17:03:10 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=205a0fe1

temporary files, tmpconst: add allowed_values

---
 roverlay/tmpconst.py |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/roverlay/tmpconst.py b/roverlay/tmpconst.py
index 3f10aaa..8519aad 100644
--- a/roverlay/tmpconst.py
+++ b/roverlay/tmpconst.py
@@ -15,7 +15,8 @@ DESCRIPTION_LIST_SPLIT_REGEX = '\s*[,;]{1}\s*'
 
 DESCRIPTION_FILE_NAME = 'DESCRIPTION'
 
-DESCRIPTION_VALID_OS_TYPES = [ "unix" ]
+# moved to <field> -> 'allowed_values'
+##DESCRIPTION_VALID_OS_TYPES = [ "unix" ]
 
 
 # note for 2012-05-25: make this struct more organized, assign real values
@@ -99,6 +100,7 @@ DESCRIPTION_FIELD_MAP = {
 		'alias' : {
 			'nocase' : [ 'OS_TYPE' ]
 		},
+		'allowed_values' : [ 'unix' ],
 	},
 	'test-default' : {
 		'default_value' : 'some default value'



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-26 13:14 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-26 13:14 UTC (permalink / raw
  To: gentoo-commits

commit:     9298e87377b76ecd093535458d4566d890c7b2e8
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat May 26 13:14:04 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat May 26 13:14:04 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=9298e873

roverlay,fileio, DescriptionReader:
	field identifier aliases now in field ['alias'] [<alias_type>]
	add ability to set default values for fields
	field flag checking improved
	modified:   roverlay/fileio.py

---
 roverlay/fileio.py |  336 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 189 insertions(+), 147 deletions(-)

diff --git a/roverlay/fileio.py b/roverlay/fileio.py
index 88cca0f..6e905b9 100644
--- a/roverlay/fileio.py
+++ b/roverlay/fileio.py
@@ -9,39 +9,34 @@ import tarfile
 # temporary import until logging is implemented
 from sys import stderr as logging
 
-
-
 # temporary import until config and real constants are implemented
 from roverlay import tmpconst as const
 
 class DescriptionReader:
+	"""Description Reader"""
 
 	@classmethod
 	def __init__ ( self ):
 		"""Initializes a DESCRIPTION file reader."""
-		self._mandatory_fields = []
+		pass
 
 	@classmethod
-	def _get_mandatory_fields ( self, force_update=False ):
-		"""Returns a list of the fields a DESCRIPTION file must define.
+	def _get_fields_with_flag ( self, flag, foce_update=False ):
 
-		arguments:
-		* force_update -- enforce creation of a new list
-		"""
+		matching_fields = []
 
-		# use previously calculated results (if item count > 0)
-		if force_update or ( not len (self._mandatory_fields) ):
-			field = None
-			mandatory = []
-			for field in const.DESCRIPTION_FIELD_MAP.keys():
-				if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-					if 'mandatory' in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
-						mandatory.append ( field )
+		field = None
+		for field in const.DESCRIPTION_FIELD_MAP.keys():
+			if flag is None:
+				matching_fields.append ( field )
+
+			elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
+				if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
+					matching_fields.append ( field )
 
-			self._mandatory_fields = mandatory
-			del field, mandatory
+		del field
+		return matching_fields
 
-		return self._mandatory_fields
 
 	@classmethod
 	def _find_field ( self , field_identifier ):
@@ -62,7 +57,7 @@ class DescriptionReader:
 
 		# save some time by prevent searching if field_id is empty
 		if not field_identifier:
-			return ''
+			return None
 
 		# search for real field names first
 		for field in const.DESCRIPTION_FIELD_MAP.keys():
@@ -73,29 +68,23 @@ class DescriptionReader:
 
 		for field in const.DESCRIPTION_FIELD_MAP.keys():
 
-			# ?TODO : DESCRIPTION_FIELD_MAP ['alias'] [<alias_types>] instead of the current structure?
-
 			# does extra information (-> alias(es)) for this field exist?
-			if isinstance ( const.DESCRIPTION_FIELD_MAP [field], dict ):
-
-				for alias_type in const.DESCRIPTION_FIELD_MAP [field] . keys():
-
-					if alias_type == 'withcase':
-
-						for alias in const.DESCRIPTION_FIELD_MAP [field] [alias_type]:
-							if field_identifier == alias:
-								return field
+			if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
 
-					elif alias_type == 'nocase':
+				if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
+					for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
+						if field_identifier == alias:
+							return field
 
-						for alias in const.DESCRIPTION_FIELD_MAP [field] [alias_type]:
-							if field_id_lower == alias.lower():
-								return field
+				if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
+					for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
+						if field_id_lower == alias.lower():
+							return field
 
-					#elif other_alias_type:
+				#if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
 
-		# returning empty string if no valid field identifier matches
-		return ''
+		# returning None if no valid field identifier matches
+		return None
 
 	@classmethod
 	def _make_values ( self, value_str, field_context=None ):
@@ -111,12 +100,16 @@ class DescriptionReader:
 
 		svalue_str = value_str.strip()
 
-		if field_context is None:
+		if not svalue_str:
+			# empty value(s)
+			return []
+
+		elif field_context is None:
 			# default return if no context given
 			return [ svalue_str ]
 
-		if self._check_fieldflag ( field_context ):
-			# have flags for field_context, check these
+		elif self._check_fieldflag ( field_context ):
+			# value str is not empty and have flags for field_context, check these
 
 			if self._check_fieldflag ( field_context, 'isList' ):
 					# split up this list (that is separated by commata and/or semicolons)
@@ -142,12 +135,9 @@ class DescriptionReader:
 		"""
 
 		if field in const.DESCRIPTION_FIELD_MAP:
-
 			if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
-
 				if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
 					return True
-
 				elif flag_to_check is None:
 					# 'flags' exist, return true
 					return True
@@ -155,52 +145,146 @@ class DescriptionReader:
 		return False
 
 	@staticmethod
-	def _get_desc_from_tarball ( tarball, pkg_name='.' ):
-		"""
-		Extracts the contents of the description file in the given tarball
-		and returns them as list of str.
+	def _get_desc_from_file ( filepath, pkg_name='.' ):
+		"""Reads a file returns the description data.
 
 		arguments:
-		* tarball -- tarball to read
-		* pkg_name -- name of the package, usually the description file is
-		               <pkg_name>/DESCRIPTION and this that arguments is
-		               required. Defaults to '.', set to None to disable.
+		* filepath -- file to read (str; path to tarball or file)
+		* pkg_name -- name of the package, in tarballs the description file
+		              is located in <pkg_name>/ and thus this argument is required.
+		              Defaults to '.', set to None to disable.
 
 		All exceptions are passed to the caller (TarError, IOErr, <custom>).
+		<filepath> can either be a tarball in which case the real DESCRIPTION
+		file is read (<pkg_name>/DESCRIPTION) or a normal file.
 		"""
 
-		logging.write ( "Starting to read tarball file '" + tarball + "' ...\n" )
+		logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
 
-		if not tarfile.is_tarfile ( tarball ):
-			# not a tarball, <todo> real exception
-			raise Exception ("tarball expected")
+		if not ( isinstance ( filepath, str ) and filepath ):
+			raise Exception ( "bad usage" )
 
-		# open a file handle <fh> for the DESCRIPTION file using a tar handle <th>
-		th = fh = None
+		# read describes how to import the lines from a file (e.g. rstrip())
+		#  fh, th are file/tar handles
+		read = th = fh = None
 
-		th = tarfile.open ( tarball, 'r' )
-		if pkg_name:
-			fh = th.extractfile (
-				os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME )
-			)
+		if tarfile.is_tarfile ( filepath ):
+			# filepath is a tarball, open tar handle + file handle
+			th = tarfile.open ( filepath, 'r' )
+			if pkg_name:
+				fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
+			else:
+				fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
+
+			# have to decode the lines
+			read = lambda lines : [ line.decode().rstrip() for line in lines ]
 		else:
-			fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
+			# open file handle only
+			fh = open ( filepath, 'r' )
+			read = lambda lines : [ line.rstrip() for line in lines ]
 
 		x = None
-		# get lines from <fh>, decode and remove end of line whitespace
-		read_lines = [ x.decode().rstrip() for x in fh.readlines() ]
-		del x
+		read_lines = read ( fh.readlines() )
+		del x, read
 
 		fh.close()
-		th.close()
-
+		if not th is None: th.close()
 		del fh, th
+
 		return read_lines
 
+	@staticmethod
+	def _get_fileinfo ( filepath ):
+		"""Returns some info about the given filepath as dict whose contents are
+			the file path, the file name ([as package_file with suffix and]
+			as filename with tarball suffix removed), the package name
+			and the package_version.
+
+		arguments:
+		* filepath --
+		"""
+
+		package_file = os.path.basename ( filepath )
+
+		filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
+
+		# todo move that separator to const
+		package_name, sepa, package_version = filename.partition ( '_' )
+
+		if not sepa:
+			# file name unexpected, tarball extraction will (probably) fail
+			#raise Exception ("file name unexpected")
+			logging.write ( "unexpected file name '" + filename + "'.\n" )
+
+		return dict (
+			filepath        = filepath,
+			filename        = filename,
+			#package_file    = package_file,
+			package_name    = package_name,
+			package_version = package_version,
+		)
+
 
 
 	@classmethod
-	def readfile ( self, file ):
+	def _verify_read_data ( self, read_data ):
+		"""Verifies and fixes (e.g. add default values) read data"""
+
+		def stats ( data ):
+			"""Temporary function that prints some info about the given data."""
+			field = None
+			logging.write ( "=== this is the list of read data ===\n" )
+			for field in read_data.keys():
+				logging.write ( field + " = " + str ( read_data [field] ) + "\n" )
+			logging.write ( "=== end of list ===\n" )
+			del field
+
+		stats ( read_data )
+
+		# "finalize" data
+		logging.write ( "Fixing data...\n" )
+		field = None
+
+		# join values to a single str
+		for field in self._get_fields_with_flag ( 'joinValues' ):
+			if field in read_data.keys():
+				read_data [field] = ' ' . join ( read_data [field] )
+
+		# verify that all necessary fields have been added and are set
+		missing_fields = dict()
+		for field in self._get_fields_with_flag ( 'mandatory' ):
+			if field in read_data:
+				if not len (read_data [field]):
+					missing_fields [field] = 'unset'
+			else:
+				missing_fields [field] = 'missing'
+
+		del field
+
+		if len (missing_fields):
+			logging.write (
+				"Verification of mandatory fields failed, the result leading to this was: " +
+				str (missing_fields) + "\n"
+			)
+
+			#<raise custom exception>
+			raise Exception ("^^^look above")
+
+		del missing_fields
+
+		# add/insert default values
+		for field in const.DESCRIPTION_FIELD_MAP.keys():
+			if not field in read_data and 'default_value' in const.DESCRIPTION_FIELD_MAP [field]:
+				read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
+
+
+		stats ( read_data )
+
+		return True
+
+
+	@classmethod
+	def readfile ( self, filepath ):
 		"""Reads a DESCRIPTION file and returns the read data if successful, else None.
 
 		arguments:
@@ -216,56 +300,50 @@ class DescriptionReader:
 		with <field value> as str and <field values> as list.
 		"""
 
-		# todo move that regex to const
-		filename = re.sub ('[.](tgz|tbz2|(tar[.](gz|bz2)))',
-			'',
-			os.path.basename ( file )
+		read_data = dict (
+			_ = DescriptionReader._get_fileinfo ( filepath )
 		)
-		# todo move that separator to const
-		package_name, sepa, package_version = filename.partition ( '_' )
-		if not sepa:
-			# file name unexpected
-			raise Exception ("file name unexpected")
 
 
 		try:
-			desc_lines = DescriptionReader._get_desc_from_tarball ( file, package_name )
+			desc_lines = DescriptionReader._get_desc_from_file (
+				filepath, read_data ['_'] ['package_name']
+			)
+
 
 		except IOError as err:
 			# <todo>
 			raise
 
-		read_data = dict()
 
 		field_context = val = line = sline = None
 		for line in desc_lines:
+
 			# using s(tripped)line whenever whitespace doesn't matter
 			sline = line.lstrip()
 
-			if not sline:
-				# empty line
+			if (not sline) or (line [0] == const.DESCRIPTION_COMMENT_CHAR):
+				# empty line or comment
 				pass
 
-			elif line [0] == const.DESCRIPTION_COMMENT_CHAR:
-				pass
-
-			elif field_context and line [0] != sline [0]:
-				# line starts with whitespace and context is set => append values
-				for val in self._make_values ( sline, field_context ):
-					read_data [field_context] . append ( val )
+			elif line [0] != sline [0]:
+				# line starts with whitespace
 
+				if field_context:
+					# context is set => append values
 
-			elif line [0] != sline [0]:
-				# line starts with whitespace and context is not set => ignore
-				pass
+					for val in self._make_values ( sline, field_context ):
+						read_data [field_context] . append ( val )
+				else:
+					# no valid context => ignore line
+					pass
 
 			else:
-				# new context, forget last one
+				# line introduces a new field context, forget last one
 				field_context = None
 
 				line_components = sline.partition ( const.DESCRIPTION_FIELD_SEPARATOR )
 
-
 				if line_components [1]:
 					# line contains a field separator, set field context
 					field_context = self._find_field ( line_components [0] )
@@ -274,10 +352,10 @@ class DescriptionReader:
 						# create a new empty list for field_context
 						read_data [field_context] = []
 
-						if len ( line_components ) == 3:
-							# add values to read_data
-							for val in self._make_values ( line_components [2], field_context ):
-								read_data [field_context] . append ( val )
+						# add values to read_data
+						#  no need to check line_components [2] 'cause [1] was a true str
+						for val in self._make_values ( line_components [2], field_context ):
+							read_data [field_context] . append ( val )
 
 					else:
 						# useless line, skip
@@ -286,57 +364,21 @@ class DescriptionReader:
 							+ line_components [0] + "'\n"
 						)
 
-					del line_components
-
 				else:
-					# how to reach this block? -- remove later
-					raise Exception ( "should-be unreachable code" )
-
-		del val, line, sline, field_context
-
-		def stats ( data ):
-			"""Temporary function that prints some info about the given data."""
-			field = None
-			logging.write ( "=== this is the list of read data ===\n" )
-			for field in read_data.keys():
-				logging.write ( field + " = " + str ( read_data [field] ) + "\n" )
-			logging.write ( "=== end of list ===\n" )
-			del field
+					# reaching this branch means that
+					#  (a) line has no leading whitespace
+					#  (b) line has no separator (:)
+					# this should not occur in description files (bad syntax?)
+					logging.write ( "***" + line_components [0] + "***\n")
+					raise Exception ( "bad file" )
 
-		stats ( read_data )
+				del line_components
 
-		# "finalize" data
-		field = None
-		for field in read_data.keys():
-			if self._check_fieldflag ( field ):
-				# has flags
-				if self._check_fieldflag ( field, 'joinValues' ):
-					read_data [field] = ' ' . join ( read_data [field] )
+		del sline, line, val, field_context
 
-		# verify that all necessary fields have been added and are set
-		missing_fields = dict()
-		for field in self._get_mandatory_fields():
-			if field in read_data:
-				if not len (read_data [field]):
-					missing_fields [field] = 'unset'
 
-			else:
-				missing_fields [field] = 'missing'
-
-		if len (missing_fields):
-			logging.write ("Verification of mandatory fields failed, the result leading to this is: " +
-				str (missing_fields) + "\n"
-			)
-
-			#<raise custom exception>
-			raise Exception ("^^^look above")
-
-		del field, missing_fields
-
-		# add default values
-
-		logging.write ( "Fixing data...\n" )
-		stats ( read_data )
-
-		return read_data
+		if self._verify_read_data ( read_data ):
+			return read_data
+		else:
+			return None
 



^ permalink raw reply related	[flat|nested] 159+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/
@ 2012-05-26 13:14 André Erdmann
  0 siblings, 0 replies; 159+ messages in thread
From: André Erdmann @ 2012-05-26 13:14 UTC (permalink / raw
  To: gentoo-commits

commit:     503c1170043d7a59ff39741ca740361340c9d508
Author:     Andre Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sat May 26 13:13:45 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sat May 26 13:13:45 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=503c1170

roverlay, ebuildcreator: minor changes

---
 roverlay/ebuildcreator.py |   80 ++++++++++++++++++++++++++------------------
 1 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/roverlay/ebuildcreator.py b/roverlay/ebuildcreator.py
index 442382e..fa648b8 100644
--- a/roverlay/ebuildcreator.py
+++ b/roverlay/ebuildcreator.py
@@ -31,23 +31,23 @@ class Ebuild:
 		"""Initializes an empty Ebuild. This is an object that can be used to
 		create text lines for an ebuild file."""
 
-		self.name        = ''
-		self.version     = ''
-		self.origin      = ''
-		self.pkg_file    = ''
-		self.depend      = ''
-		self.rdepend     = ''
-		self.rsuggests   = ''
-		self.description = ''
+		#self.name        = ''
+		#self.version     = ''
+		#self.origin      = ''
+		#self.pkg_file    = ''
+		#self.depend      = ''
+		#self.rdepend     = ''
+		#self.rsuggests   = ''
+		#self.description = ''
 
 		# temporary var
-		self.TODO = ''
+		#self.TODO = ''
 
 		# this will be a list of str when exported data have been calculated
 		self._ebuild_export = None
 
 	@classmethod
-	def get_ebuild ( self, force_update=False ):
+	def get_ebuild ( self, description_data, force_update=False ):
 		"""
 		Wrapper function that returns ebuild 'export' data.
 		This is a list of str that has no newline chars at the end of each str.
@@ -57,7 +57,7 @@ class Ebuild:
 
 		"""
 		if force_update or (self._ebuild_export is None):
-			self._ebuild_export = self._make_export()
+			self._ebuild_export = self._make_export ( description_data )
 
 		return self._ebuild_export
 
@@ -98,10 +98,31 @@ class Ebuild:
 		# catch failure
 		return False
 
+		@classmethod
+		def _make_ebuild_lines ( self, ebuild_content ):
+			ebuild_export = []
+			last_line_empty = False
+			line = None
+
+			# remove repeated newlines ('repoman sez: ...')
+			for line in ebuild_content:
+				line = line.rstrip()
+				if line:
+					last_line_empty = False
+				elif not last_line_empty:
+					last_line_empty = True
+				else:
+					continue
+
+				ebuild_export.append ( line )
+
+			del last_line_empty, line
+			return ebuild_content
+
 
 
 	@staticmethod
-	def _get_fileheader ( ebuild_header_file=None ):
+	def _get_ebuild_header ( ebuild_header_file=None ):
 		"""Reads and returns the content of an ebuild header file.
 		This is a normal file that can be included in ebuilds.
 		Every header file will only be read on first access, it's content will
@@ -152,7 +173,7 @@ class Ebuild:
 			return indent_level * EBUILD_INDENT + varname + '""'
 
 	@classmethod
-	def _make_export ( self, ebuild_header=None ):
+	def _make_export ( self, description_data, ebuild_header=None ):
 		"""Creates ebuild data that can be written into stdout or a file
 
 		arguments:
@@ -163,13 +184,21 @@ class Ebuild:
 
 		# this method is todo
 
+		if not isinstance (description_data, dict):
+			#todo
+			raise Exception ( "bad description data" )
+
 		errors = dict()
 
-		ebuild_content = _get_fileheader ( ebuild_header )
+		ebuild_content = Ebuild._get_ebuild_header ( ebuild_header )
 
 		# repeated and leading empty lines will be removed later
 		ebuild_content.append ( "" )
 
+		# the code below this line does not work
+		return
+		#raise Exception ( "under construction ..." )
+
 		if self.pkg_file:
 			ebuild_content.append ( _make_var ( "PKG_FILE" , self.pkg_file ) )
 		else:
@@ -225,27 +254,10 @@ class Ebuild:
 			raise Exception ( "^^^missing components for ebuild^^^" )
 			#return None
 
-		ebuild_export = []
-		last_line_empty = False
-		line = None
-
-		# remove repeated newlines ('repoman sez: ...')
-		for line in ebuild_content:
-			line = line.rstrip()
-			if line:
-				last_line_empty = False
-			elif not last_line_empty:
-				last_line_empty = True
-			else:
-				continue
-
-			ebuild_export.append ( line )
-
-
-		del last_line_empty, line, ebuild_content
-		return ebuild_export
+		return self._make_ebuild_lines ( ebuild_content )
 
 class EbuildCreator:
+# could move this to Ebuild
 
 		@classmethod
 		def __init__ ( self,  description_data ):
@@ -290,6 +302,8 @@ class EbuildCreator:
 
 			# <dep resolution here?>
 
+			ebuild.get_ebuild ( self._description_data )
+
 			# todo
 			return None
 



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

end of thread, other threads:[~2015-01-26 17:41 UTC | newest]

Thread overview: 159+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-29 17:09 [gentoo-commits] proj/R_overlay:master commit in: roverlay/ André Erdmann
  -- strict thread matches above, loose matches on Subject: below --
2015-01-26 17:41 André Erdmann
2015-01-26 17:41 André Erdmann
2014-07-18 16:20 André Erdmann
2014-07-18  2:50 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-18  2:28 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-16 15:14 André Erdmann
2014-06-05 22:09 André Erdmann
2014-04-01 16:38 André Erdmann
2014-02-16 16:30 André Erdmann
2014-02-15 19:49 André Erdmann
2014-02-15 19:49 André Erdmann
2014-01-25 18:14 André Erdmann
2013-12-11 18:40 André Erdmann
2013-12-11 18:40 André Erdmann
2013-09-23 15:30 André Erdmann
2013-09-20 15:57 André Erdmann
2013-09-19 15:00 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-16 13:43 André Erdmann
2013-09-13 15:10 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-11 11:14 André Erdmann
2013-09-11 10:19 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-03 15:50 André Erdmann
2013-09-02 12:27 André Erdmann
2013-09-02  8:44 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-28 15:54 André Erdmann
2013-08-27 15:39 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-19 15:42 André Erdmann
2013-08-16 14:05 André Erdmann
2013-08-16 11:02 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-13  8:56 André Erdmann
2013-08-13  8:56 André Erdmann
2013-08-13  8:56 André Erdmann
2013-08-12  8:28 André Erdmann
2013-08-12  8:18 André Erdmann
2013-08-07 16:10 André Erdmann
2013-08-02 14:30 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-01 12:44 André Erdmann
2013-08-01 12:44 André Erdmann
2013-07-29 14:56 André Erdmann
2013-07-29  8:55 André Erdmann
2013-07-26 13:02 André Erdmann
2013-07-23  7:51 André Erdmann
2013-07-23  7:51 André Erdmann
2013-07-19 18:00 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-23  7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-17 18:05 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-17 18:05 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-15 22:31 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-16 16:36 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-12 13:57 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-22 15:24 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-19 18:59 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-13 16:34 André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-04 21:06 André Erdmann
2013-04-25 16:44 André Erdmann
2013-04-25 16:44 André Erdmann
2013-03-05 11:27 André Erdmann
2013-02-09 20:45 André Erdmann
2013-02-05 17:48 André Erdmann
2013-02-05 17:48 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2012-10-02 10:04 André Erdmann
2012-08-20 11:16 André Erdmann
2012-08-13 18:07 André Erdmann
2012-08-09  9:26 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-07  8:50 André Erdmann
2012-08-02 15:14 André Erdmann
2012-08-01  7:25 André Erdmann
2012-07-31 17:51 André Erdmann
2012-07-30  8:52 André Erdmann
2012-07-30  8:52 André Erdmann
2012-07-24 16:59 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30  8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-18 16:49 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30  8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 [gentoo-commits] proj/R_overlay:depres_wip " André Erdmann
2012-07-16 16:15 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-10 17:43 André Erdmann
2012-07-09 17:19 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-03 17:48 André Erdmann
2012-06-28 13:29 André Erdmann
2012-06-26 15:42 André Erdmann
2012-06-25 18:19 André Erdmann
2012-06-21 16:55 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-18 16:27 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-12 17:17 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-05 17:30 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 15:43 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 15:46 André Erdmann
2012-05-31 18:24 André Erdmann
2012-05-30 20:15 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-26 13:14 André Erdmann
2012-05-26 13:14 André Erdmann

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