public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/portage/metadata/, roverlay/static/, roverlay/, ...
@ 2012-06-19 18:19 André Erdmann
  0 siblings, 0 replies; only message in thread
From: André Erdmann @ 2012-06-19 18:19 UTC (permalink / raw
  To: gentoo-commits

commit:     2afa2439d20402b7cb7af0ca12edd5bb0c269bdc
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Jun 19 18:16:01 2012 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Jun 19 18:16:01 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=2afa2439

roverlay, 2012-06-19

* added Manifest creation to the overlay module
* code moved/adjusted for R package -> overlay conversion
* removed unnecessary code in ebuild module

	new file:   roverlay/ebuild/__init__.py
	renamed:    roverlay/portage/ebuild.py -> roverlay/ebuild/construction.py
	new file:   roverlay/ebuild/creation.py
	renamed:    roverlay/portage/manifest.py -> roverlay/manifest/__init__.py
	renamed:    roverlay/portage/manifesthelpers.py -> roverlay/manifest/helpers.py
	renamed:    roverlay/portage/metadata/creation.py -> roverlay/metadata/__init__.py
	renamed:    roverlay/portage/metadata/abstractnodes.py -> roverlay/metadata/abstractnodes.py
	renamed:    roverlay/portage/metadata/nodes.py -> roverlay/metadata/nodes.py
	renamed:    roverlay/portage/overlay/root.py -> roverlay/overlay/__init__.py
	renamed:    roverlay/portage/overlay/category.py -> roverlay/overlay/category.py
	renamed:    roverlay/portage/overlay/package.py -> roverlay/overlay/package.py
	renamed:    roverlay/portage/packageinfo.py -> roverlay/packageinfo.py
	deleted:    roverlay/portage/__init__.py
	deleted:    roverlay/portage/ebuildcreator.py
	deleted:    roverlay/portage/ebuildjob.py
	deleted:    roverlay/portage/metadata/__init__.py
	deleted:    roverlay/portage/overlay/__init__.py
	new file:   roverlay/static/__init__.py
	new file:   roverlay/static/depres.py

---
 roverlay/ebuild/__init__.py                        |   38 +++
 .../{portage/ebuild.py => ebuild/construction.py}  |  170 ++---------
 roverlay/ebuild/creation.py                        |  203 ++++++++++++
 .../{portage/manifest.py => manifest/__init__.py}  |    7 +-
 .../manifesthelpers.py => manifest/helpers.py}     |    0
 .../metadata/creation.py => metadata/__init__.py}  |   15 +-
 roverlay/{portage => }/metadata/abstractnodes.py   |    0
 roverlay/{portage => }/metadata/nodes.py           |    2 +-
 .../overlay/root.py => overlay/__init__.py}        |   26 +-
 roverlay/{portage => }/overlay/category.py         |   72 +++--
 roverlay/{portage => }/overlay/package.py          |  165 +++++++---
 roverlay/{portage => }/packageinfo.py              |   39 ++-
 roverlay/portage/ebuildcreator.py                  |  184 -----------
 roverlay/portage/ebuildjob.py                      |  333 --------------------
 roverlay/static/__init__.py                        |    5 +
 roverlay/static/depres.py                          |   29 ++
 16 files changed, 510 insertions(+), 778 deletions(-)

diff --git a/roverlay/ebuild/__init__.py b/roverlay/ebuild/__init__.py
new file mode 100644
index 0000000..259a352
--- /dev/null
+++ b/roverlay/ebuild/__init__.py
@@ -0,0 +1,38 @@
+# R Overlay -- ebuild creation, ebuild class
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+class Ebuild ( object ):
+
+	def __init__ ( self, content, header=None ):
+		"""Initializes an Ebuild that has text content and optionally a
+		header (text, too).
+
+		arguments:
+		* content --
+		* header  --
+		"""
+		self.content = content
+		self.header  = header
+	# --- end of __init__ (...) ---
+
+	def write ( self, fh, header=None ):
+		"""Write the ebuild into a file-like object.
+
+		arguments:
+		* fh -- file handle
+		"""
+		if not self.content:
+			raise Exception ( "ebuild is empty!" )
+
+		if header is None:
+			if not self.header is None:
+				fh.write ( self.header )
+				fh.write ( '\n' )
+		else:
+			fh.write ( header )
+			fh.write ( '\n' )
+
+		fh.write ( self.content )
+		fh.write ( '\n' )
+	# --- end of write_fh (...) ---

diff --git a/roverlay/portage/ebuild.py b/roverlay/ebuild/construction.py
similarity index 65%
rename from roverlay/portage/ebuild.py
rename to roverlay/ebuild/construction.py
index a435f5c..ed5bca5 100644
--- a/roverlay/portage/ebuild.py
+++ b/roverlay/ebuild/construction.py
@@ -6,10 +6,13 @@ import copy
 
 import roverlay.config
 
-from roverlay.util import shorten_str
+from roverlay.util   import shorten_str
+from roverlay.ebuild import Ebuild
 
 
-class Ebuild ( object ):
+class EbuildConstruction ( object ):
+	"""Class that helps to create Ebuild objects."""
+
 	EBUILD_INDENT = roverlay.config.get ( 'EBUILD.indent', '\t' )
 
 	ADD_REMAP = {
@@ -27,80 +30,37 @@ class Ebuild ( object ):
 	}
 
 	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.
+		"""Initializes an EbuildConstruction object.
 
 		arguments:
-		* logger -- logger for this Ebuild
+		* logger --
 		"""
-
 		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
 		self.has_rsuggests = False
 
+		# elements in data are either a str or a list of str
+		self._data = dict ()
 	# --- end of __init__ (...) ---
 
-	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:
-			# determine the ebuild name first
-			self._ebuild_name = self.suggest_name()
-			del self._data
-			self._data = None
-
-	# --- end of cleanup (...) ---
-
-	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 (...) ---
-
-	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 get_ebuild ( self ):
+		"""Creates and returns an Ebuild."""
+		lines = '\n'.join ( self._make_ebuild_lines() )
+		return Ebuild ( lines, header=None )
+	# --- end of get_ebuild (...) ---
 
 	def add ( self, key, value, append=True ):
-		"""Adds data to this Ebuild.
+		"""Adds data.
 
 		arguments:
-		* key -- identifier of the data (e.g. DEPEND).
-		         May be remapped (e.g. merging 'Title' and 'Description')
-		         or even refused here
-		* value --
+		* key    -- identifier of the data (e.g. DEPEND).
+		             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.
 
-		raises: Exception when ebuild data are readonly
+		returns: None (implicit)
 		"""
 		if self._data is None:
 			# -- todo
@@ -125,96 +85,8 @@ class Ebuild ( object ):
 
 	# --- end of add (...) ---
 
-	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
-			except IOError as err:
-				self.logger.exception ( err )
-				raise
-
-		else:
-				self.logger.warning (
-					'Cannot write ebuild - it\'s empty! '
-					'(check with has_ebuild() before calling this method.)'
-				)
-
-	# --- end of write (...) ---
-
-	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_dir_name ( self ):
-		"""Suggests a direcory name for this Ebuild."""
-		if self._data is None:
-			return self._ebuild_name.partition ( '-' ) [0]
-		elif 'pkg_name' in self._data:
-			return self._data ['pkg_name']
-		else:
-			return self.suggest_name().partition ( '-' ) [0]
-	# --- 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 empty string
-		"""
-
-		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%i' % rev )
-
-			return '-'.join ( name_components )
-
-		else:
-			return fallback_name
-
-	# --- end of suggest_name (...) ---
-
 	def _make_ebuild_lines ( self ):
-		"""Creates text lines for this Ebuild.
+		"""Creates text lines for the Ebuild.
 		It assumes that enough data to do this are available.
 		Exceptions (KeyError, NameError, ...) are passed if that's not the case.
 		"""

diff --git a/roverlay/ebuild/creation.py b/roverlay/ebuild/creation.py
new file mode 100644
index 0000000..eed54b2
--- /dev/null
+++ b/roverlay/ebuild/creation.py
@@ -0,0 +1,203 @@
+# R Overlay -- ebuild creation, "job" module
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import logging
+
+import roverlay.static.depres
+
+from roverlay.ebuild.construction        import EbuildConstruction
+from roverlay.rpackage.descriptionreader import DescriptionReader
+
+# move this to const / config
+DEPENDENCY_FIELDS = {
+	'R_SUGGESTS' : [ 'Suggests' ],
+	'DEPENDS'    : [ 'Depends', 'Imports' ],
+	'RDEPENDS'   : [ 'LinkingTo', 'SystemRequirements' ]
+}
+
+LOGGER = logging.getLogger ( 'EbuildCreation' )
+
+class EbuildCreation ( object ):
+
+	def __init__ ( self, package_info, depres_channel_spawner=None ):
+
+		self.logger = LOGGER.getChild ( package_info ['name'] )
+		self.package_info = package_info
+
+		if depres_channel_spawner is None:
+			self.request_resolver = roverlay.static.depres.get_ebuild_channel
+		else:
+			self.request_resolver = depres_channel_spawner
+
+		# > 0 busy/working; 0 == done,success; < 0 done,fail
+		self.status = 1
+
+		self.package_info.set_readonly()
+	# --- end of __init__ (...) ---
+
+	def done()    : return self.status  < 1
+	def busy()    : return self.status  > 0
+	def success() : return self.status == 0
+	def fail()    : return self.status  < 0
+
+
+	def _resolve_dependencies ( self, ebuilder ):
+		if self.request_resolver is None:
+			self.logger.warning (
+				"Cannot resolve dependencies, no resolver available!"
+			)
+			return True
+
+		res = None
+		# -- end pre func block --
+
+		def init_channels():
+			# collect dep strings and initialize resolver channels
+			desc     = self.package_info ['desc_data']
+			channels = dict()
+
+			def get_resolver ( dependency_type ):
+				if dependency_type not in channels:
+					channels [dependency_type] = self.request_resolver (
+						dependency_type,
+						self.logger
+					)
+				return channels [dependency_type]
+			# --- end of get_resolver (...) ---
+
+			dep_type = desc_field = None
+
+			for dep_type in DEPENDENCY_FIELDS:
+				resolver = None
+
+				for desc_field in DEPENDENCY_FIELDS [dep_type]:
+					if desc_field in desc:
+						if not resolver:
+							resolver = get_resolver ( dep_type )
+
+						if isinstance ( desc [desc_field], str ):
+							resolver.add_dependency ( desc [desc_field] )
+						elif hasattr ( desc [desc_field], '__iter__' ):
+							resolver.add_dependencies ( desc [desc_field] )
+						else:
+							logger.warning (
+								"Cannot add dependency '%s'." % desc [desc_field]
+						)
+					# -- if desc_field
+				# -- for desc_field
+			# -- for dep_type
+			return channels
+		# --- end of init_resolvers (...) ---
+
+		def try_resolve():
+			for r in res.values():
+				if r.satisfy_request() is None:
+					return False
+			return True
+		# --- end of try_resolve (...) ---
+
+		# TODO
+		# replace try_resolve with
+		#  False in ( r.satisfy_request() for r in res.values() )
+		# ?
+		res     = init_channels()
+		if not res: return True
+		success = False
+
+
+		if try_resolve():
+			for dep_type, resolver in res.items():
+				deplist = list ( filter ( None, resolver.collect_dependencies() ) )
+
+				if deplist is None:
+					## FIXME: false positive: "empty" channel
+					raise Exception (
+						'dep_resolver is broken: '
+						'lookup() returns None but satisfy_request() says ok.'
+					)
+				elif hasattr ( deplist, '__iter__' ):
+					# add dependencies in no_append/override mode
+					self.logger.debug ( "adding %s to %s", deplist, dep_type )
+					ebuilder.add ( dep_type, deplist, False )
+				else:
+					raise Exception ( "dep_resolver is broken: iterable expected!" )
+			# -- for dep_type,..
+
+			success = True
+
+		# tell the dep resolver channels that we're done
+		for r in res.values(): r.close()
+		return success
+	# --- end of resolve_dependencies (...) ---
+
+	def _make_ebuild ( self ):
+		desc = self.package_info ['desc_data']
+		if desc is None:
+			self.logger (
+				'desc empty- cannot create an ebuild for this package.'
+			)
+			return None
+
+		ebuilder = EbuildConstruction ( self.logger )
+
+		have_desc = False
+
+		if 'Title' in desc:
+			ebuilder.add ( 'DESCRIPTION', desc ['Title'] )
+			have_desc = True
+
+		if 'Description' in desc:
+			ebuilder.add (
+				'DESCRIPTION',
+				( '// ' if have_description else '' ) + desc ['Description']
+			)
+
+
+		ebuilder.add ( 'SRC_URI', self.package_info ['package_url'] )
+
+		if self._resolve_dependencies():
+			return ( ebuilder.get_ebuild(), ebuilder.has_rsuggests )
+
+		return None
+	# --- end of _make_ebuild (...) ---
+
+	def run ( self ):
+		if self.status < 1:
+			raise Exception ( "Cannot run again." )
+
+		try:
+			if self.package_info.get ( 'desc_data',
+				fallback_value=None, do_fallback=True ) is None:
+
+				logging.warning ( 'Reading description data now.' )
+				reader = DescriptionReader (
+					self.package_info,
+					logger=self.logger,
+					read_now=True
+				)
+				self.package_info.set_writeable()
+				self.package_info.update (
+					desc_data=reader.get_desc ( run_if_unset=False )
+				)
+				del reader
+			# -- if
+
+			self.package_info.set_readonly()
+
+			ebuild_info = self._make_ebuild()
+			if ebuild_info is None:
+				self.status = -1
+			else:
+				self.package_info.set_writeable()
+				self.package_info.update (
+					ebuild=ebuild_info   [0],
+					suggests=ebuild_info [1]
+				)
+				self.package_info.set_readonly()
+				self.status = 0
+		except Exception as e:
+			# log this and set status to fail
+			self.status = -10
+			self.logger.exception ( e )
+	# --- end of run (...) ---

diff --git a/roverlay/portage/manifest.py b/roverlay/manifest/__init__.py
similarity index 83%
rename from roverlay/portage/manifest.py
rename to roverlay/manifest/__init__.py
index 79e241c..b95a855 100644
--- a/roverlay/portage/manifest.py
+++ b/roverlay/manifest/__init__.py
@@ -1,14 +1,11 @@
 # R Overlay -- Manifest creation for ebuilds
 # Copyright 2006-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-
-
 import logging
 
-import roverlay.portage.manifesthelpers
+from roverlay.manifest import helpers
 
-_MANIFEST_IMPLEMENTATION = \
-	roverlay.portage.manifesthelpers.ExternalManifestCreation
+_MANIFEST_IMPLEMENTATION = helpers.ExternalManifestCreation
 
 
 def create_manifest ( package_info, nofail=False ):

diff --git a/roverlay/portage/manifesthelpers.py b/roverlay/manifest/helpers.py
similarity index 100%
rename from roverlay/portage/manifesthelpers.py
rename to roverlay/manifest/helpers.py

diff --git a/roverlay/portage/metadata/creation.py b/roverlay/metadata/__init__.py
similarity index 86%
rename from roverlay/portage/metadata/creation.py
rename to roverlay/metadata/__init__.py
index d2f133c..82821bb 100644
--- a/roverlay/portage/metadata/creation.py
+++ b/roverlay/metadata/__init__.py
@@ -4,26 +4,27 @@
 
 import roverlay.config
 
-from roverlay.portage.metadata import nodes
+from roverlay.metadata import nodes
 
 class MetadataJob ( object ):
 	"""R package description data -> metadata.xml interface."""
 
-	def __init__ ( self, package_info, logger ):
+	def __init__ ( self, logger ):
 		"""Initializes a MetadataJob.
 
 		arguments:
-		* package_info -- reserved for future usage
-		* logger       -- logger to use (this instance won't call getChild)
+		(((* package_info -- reserved for future usage)))
+		* logger       -- parent logger to use
 		"""
-		self.logger    = logger
+		self.logger    = logger.getChild ( 'metadata' )
 		self._metadata = nodes.MetadataRoot()
 		# reserved for future usage ("dominant ebuilds": when ebuildjobs
 		# share one metadata instance etc.)
 		self.package_info = None
+		self.filename     = 'metadata.xml'
 	# --- end of __init__ (...) ---
 
-	def update ( self, desc_data, package_info ):
+	def update ( self, package_info ):
 		"""Updates the metadata using the given description data.
 
 		It's expected that this method is called when Ebuild creation is done.
@@ -34,7 +35,7 @@ class MetadataJob ( object ):
 
 		returns: None (implicit)
 		"""
-		pass
+		desc_data = package_info ['desc_data']
 
 		mref = self._metadata
 

diff --git a/roverlay/portage/metadata/abstractnodes.py b/roverlay/metadata/abstractnodes.py
similarity index 100%
rename from roverlay/portage/metadata/abstractnodes.py
rename to roverlay/metadata/abstractnodes.py

diff --git a/roverlay/portage/metadata/nodes.py b/roverlay/metadata/nodes.py
similarity index 98%
rename from roverlay/portage/metadata/nodes.py
rename to roverlay/metadata/nodes.py
index 36bf22d..f35f8da 100644
--- a/roverlay/portage/metadata/nodes.py
+++ b/roverlay/metadata/nodes.py
@@ -3,7 +3,7 @@
 # Distributed under the terms of the GNU General Public License v2
 
 # import abstract nodes
-from roverlay.portage.metadata.abstractnodes import \
+from roverlay.metadata.abstractnodes import \
 	MetadataNode, MetadataNodeNamedAccess, MetadataLeaf
 
 

diff --git a/roverlay/portage/overlay/root.py b/roverlay/overlay/__init__.py
similarity index 94%
rename from roverlay/portage/overlay/root.py
rename to roverlay/overlay/__init__.py
index 086cab4..081f0b8 100644
--- a/roverlay/portage/overlay/root.py
+++ b/roverlay/overlay/__init__.py
@@ -9,7 +9,7 @@ import os
 
 from roverlay import config, util
 
-from roverlay.portage.overlay.category import Category
+from roverlay.overlay.category import Category
 
 DEFAULT_USE_DESC = '\n'.join ( [
 	'byte-compile - enable byte compiling',
@@ -95,16 +95,6 @@ class Overlay ( object ):
 		) . add ( package_info )
 	# --- end of add (...) ---
 
-	def ls ( self ):
-		"""Returns a set of ebuilds/metadata stored in this overlay."""
-		return frozenset (
-			( os.path.join ( n, c.ls() ) for n, c in self._categories.items() )
-		)
-	# --- end of ls (...) ---
-
-	def __str__ ( self ): return '\n'.join ( self.ls() )
-	# --- end of __str__ ---
-
 	def show ( self, **show_kw ):
 		"""Presents the ebuilds/metadata stored in this overlay.
 
@@ -167,6 +157,20 @@ class Overlay ( object ):
 			cat.generate_metadata ( **metadata_kw )
 	# --- end of generate_metadata (...) ---
 
+	def generate_manifest ( self, **manifest_kw ):
+		"""Generates Manifest files for all ebuilds in this overlay that exist
+		physically/in filesystem.
+		Manifest files are automatically created when calling write().
+
+		arguments:
+		* **manifest_kw -- see PackageDir.generate_manifest(...)
+
+		returns: None (implicit)
+		"""
+		for cat in self._categories.values():
+			cat.generate_manifest ( **manifest_kw )
+	# --- end of generate_manifest (...) ---
+
 	def _write_profiles_dir ( self, only_active_categories=True ):
 		"""Creates and updates the profiles/ dir.
 

diff --git a/roverlay/portage/overlay/category.py b/roverlay/overlay/category.py
similarity index 55%
rename from roverlay/portage/overlay/category.py
rename to roverlay/overlay/category.py
index ff497f7..768f296 100644
--- a/roverlay/portage/overlay/category.py
+++ b/roverlay/overlay/category.py
@@ -5,14 +5,20 @@
 import threading
 import os.path
 
-
-from roverlay.portage.overlay.package import PackageDir
+from roverlay.overlay.package import PackageDir
 
 import roverlay.util
 
 class Category ( object ):
 
 	def __init__ ( self, name, logger, directory ):
+		"""Initializes a overlay/portage category (such as 'app-text', 'sci-R').
+
+		arguments:
+		* name      -- name of the category
+		* logger    -- parent logger
+		* directory -- filesystem location
+		"""
 		self.logger            = logger.getChild ( name )
 		self.name              = name
 		self._lock             = threading.RLock()
@@ -21,25 +27,20 @@ class Category ( object ):
 	# --- end of __init__ (...) ---
 
 	def empty ( self ):
+		"""Returns True if this category contains 0 ebuilds."""
 		return \
 			len ( self._subdirs ) == 0 or \
 			not False in ( d.empty() for d in self._subdirs )
 	# --- end of empty (...) ---
 
-	def set_fs_location ( self, directory ):
-		self._lock.acquire()
-		self.physical_location = directory
-
-		if not directory is None:
-			for pkg_name, pkg in self._subdirs.items():
-				pkg.set_fs_location (
-					os.path.join ( directory, pkg_name )
-				)
+	def add ( self, package_info ):
+		"""Adds a package to this category.
 
-		self._lock.release()
-	# --- end of set_fs_location (...) ---
+		arguments:
+		* package_info --
 
-	def add ( self, package_info ):
+		returns: None (implicit)
+		"""
 		# TODO make keys available
 		pkg_name = package_info ['name']
 
@@ -58,28 +59,47 @@ class Category ( object ):
 	# --- end of add (...) ---
 
 	def generate_metadata ( self, **metadata_kw ):
+		"""Generates metadata for all packages in this category.
+		Metadata are automatically generated when calling write().
+
+		arguments:
+		* **metadata_kw -- see PackageDir.generate_metadata(...)
+
+		returns: None (implicit)
+		"""
 		for package in self._subdirs.values():
 			package.generate_metadata ( **metadata_kw )
 	# --- end of generate_metadata (...) ---
 
+	def generate_manifest ( self, **manifest_kw ):
+		"""Generates Manifest files for all packages in this category.
+		Manifest files are automatically created when calling write().
+
+		arguments:
+		* **manifest_kw -- see PackageDir.generate_manifest(...)
+
+		returns: None (implicit)
+		"""
+		for package in self._subdirs.values():
+			package.generate_manifest ( **manifest_kw )
+	# --- end of generate_manifest (...) ---
+
 	def show ( self, **show_kw ):
+		"""Prints this category (its ebuild and metadata files).
+
+		returns: None (implicit)
+		"""
 		for package in self._subdirs.values():
 			package.show ( **show_kw )
 	# --- end of show (...) ---
 
-	def write ( self ):
+	def write ( self, **write_kw ):
+		"""Writes this category to its filesystem location.
+
+		returns: None (implicit)
+		"""
 		for package in self._subdirs.values():
 			if package.physical_location and not package.empty():
 				roverlay.util.dodir ( package.physical_location )
-				package.write()
-
+				package.write ( **write_kw )
 	# --- end of write (...) ---
-
-	def ls ( self ):
-		return frozenset (
-			( os.path.join ( n, p.ls() ) for n, p in self._subdirs.items() )
-		)
-
-	def __str__ ( self ): return '\n'.join ( self.ls() )
-
-

diff --git a/roverlay/portage/overlay/package.py b/roverlay/overlay/package.py
similarity index 53%
rename from roverlay/portage/overlay/package.py
rename to roverlay/overlay/package.py
index 9fc0112..d43ec1f 100644
--- a/roverlay/portage/overlay/package.py
+++ b/roverlay/overlay/package.py
@@ -6,17 +6,22 @@ import threading
 import os.path
 import sys
 
-from roverlay.portage.metadata.creation import MetadataJob
+from roverlay.metadata import MetadataJob
 
 SUPPRESS_EXCEPTIONS = True
 
 class PackageDir ( object ):
 
-	# TODO: do Manifest creation here
-
 	def __init__ ( self, name, logger, directory ):
+		"""Initializes a PackageDir which contains ebuilds, metadata and
+		a Manifest file.
+
+		arguments:
+		* name      -- name of the directory (${PN} in ebuilds)
+		* logger    -- parent logger
+		* directory -- filesystem location of this PackageDir
+		"""
 		self.logger            = logger.getChild ( name )
-		# Lock or RLock? (TODO)
 		self._lock             = threading.RLock()
 		self._packages         = dict()
 		self._metadata         = None
@@ -24,12 +29,12 @@ class PackageDir ( object ):
 	# --- end of __init__ (...) ---
 
 	def empty ( self ):
+		"""Returns True if no ebuilds stored, else False."""
 		return len ( self._packages ) == 0
-
-	def set_fs_location ( self, directory ):
-		self.physical_location = directory
+	# --- end of empty (...) ---
 
 	def _get_metadata_filepath ( self ):
+		"""Returns the path to the metadata file."""
 		return os.path.join (
 			'??' if self.physical_location is None else self.physical_location,
 			self._metadata.filename
@@ -37,6 +42,11 @@ class PackageDir ( object ):
 	# --- end of _get_metadata_filepath (...) ---
 
 	def _get_ebuild_filepath ( self, pvr ):
+		"""Returns the path to the ebuild file.
+
+		arguments:
+		* pvr -- version number with the revision (${PVR} in ebuilds)
+		"""
 		filename = "%s-%s.ebuild" % ( self.name, pvr )
 		return os.path.join (
 			'??' if self.physical_location is None else self.physical_location,
@@ -45,6 +55,12 @@ class PackageDir ( object ):
 	# --- end of _get_ebuild_filepath (...) ---
 
 	def write ( self ):
+		"""Writes this directory to its (existent!) filesystem location.
+
+		returns: None (implicit)
+
+		raises: !! TODO
+		"""
 		if self.physical_location is None:
 			raise Exception ( "cannot write - no directory assigned!" )
 
@@ -53,6 +69,7 @@ class PackageDir ( object ):
 
 		# mkdir not required here, overlay.Category does this
 
+		# write ebuilds
 		for ver, p_info in self._packages.items():
 			fh = None
 			try:
@@ -61,40 +78,51 @@ class PackageDir ( object ):
 
 				fh = open ( efile, 'w' )
 				ebuild.write ( fh )
+				if fh: fh.close()
 
 				# adjust owner/perm? TODO
 				# chmod 0644 or 0444
 				# chown 250.250
 
+				# this marks the package as 'written to fs'
+				# TODO update PackageInfo
+				p_info ['ebuild_filepath'] = efile
+
 				self.logger.info ( "Wrote ebuild %s." % efile )
 			except IOError as e:
+				if fh: fh.close()
 				self.logger.error ( "Couldn't write ebuild %s." % efile )
 				self.logger.exception ( e )
 
-			finally:
-				if fh: fh.close()
-				fh = None
-
+		# write metadata
 		fh = None
 		try:
 			mfile = self._get_metadata_filepath()
 
 			fh    = open ( mfile, 'w' )
 			self._metadata.write ( fh )
+			if fh: fh.close()
 
 		except IOError as e:
+			if fh: fh.close()
 			self.logger.error ( "Failed to write metadata at %s." % mfile )
 			self.logger.exception ( e )
-		finally:
-			if fh: fh.close()
-			del fh
 
-		# !! TODO write Manifest here
+		self.generate_manifest()
 
 		self._lock.release()
 	# --- end of write (...) ---
 
 	def show ( self, stream=sys.stderr ):
+		"""Prints this dir (the ebuilds and the metadata) into a stream.
+
+		arguments:
+		* stream -- stream to use, defaults to sys.stderr
+
+		returns: None (implicit)
+
+		raises: !! TODO
+		"""
 		self._lock.acquire()
 		self._regen_metadata()
 
@@ -115,23 +143,44 @@ class PackageDir ( object ):
 
 
 		self._lock.release()
+	# --- end of show (...) ---
 
-	def _latest_package ( self ):
-		"""Returns the package info with the highest version number."""
+	def _latest_package ( self, pkg_filter=None, use_lock=False ):
+		"""Returns the package info with the highest version number.
+
+		arguments:
+		* pkg_filter -- either None or a callable,
+		                 None: do not filter packages
+		                 else: ignore package if it does not pass the filter
+		* use_lock   -- if True: hold lock while searching
+		"""
 		first  = True
 		retver = None
 		retpkg = None
-		for p in self._packages.values():
-			newver = p ['version']
-			if first or newver > retver:
-				retver = newver
-				retpkg = p
-				first  = False
 
+		if use_lock: self._lock.acquire()
+		for p in self._packages.values():
+			if pkg_filter is None or pkg_filter ( p ):
+				newver = p ['version']
+				if first or newver > retver:
+					retver = newver
+					retpkg = p
+					first  = False
+
+		if use_lock: self._lock.release()
 		return retpkg
 	# --- end of _latest_package (...) ---
 
 	def add ( self, package_info ):
+		"""Adds a package to this PackageDir.
+
+		arguments:
+		* package_info --
+
+		returns: success as bool
+
+		raises: Exception when ebuild already exists.
+		"""
 		# !! p info key TODO
 		shortver = package_info ['ebuild_verstr']
 
@@ -160,25 +209,38 @@ class PackageDir ( object ):
 		self._packages [shortver] = package_info
 
 		self._lock.release()
+		return True
 	# --- end of add (...) ---
 
 	def _regen_metadata ( self ):
+		"""Regenerates the metadata."""
 		self.generate_metadata (
 			skip_if_existent=True,
-			use_all_packages=True,
+			use_all_packages=False,
 			use_old_metadata=False
 		)
+	# --- end of _regen_metadata (...) ---
 
 	def generate_metadata (
 		self,
 		skip_if_existent=False, use_all_packages=False, use_old_metadata=False
 	):
+		"""Creates metadata for this package.
+
+		arguments:
+		* skip_if_existent -- do not create if metadata already exist
+		* use_all_packages -- TODO
+		* use_old_metadata -- TODO
+		"""
+		if use_old_metadata or use_all_packages:
+				raise Exception ( "using >1 package for metadata.xml is TODO!" )
+
 		if skip_if_existent and not self._metadata is None:
 			return
 
 		self._lock.acquire()
 
-		if not use_old_metadata or self._metadata is None:
+		if self._metadata is None or not use_old_metadata:
 			del self._metadata
 			self._metadata = MetadataJob ( self.logger )
 
@@ -188,32 +250,41 @@ class PackageDir ( object ):
 		else:
 			self._metadata.update ( _latest_package() )
 
-
 		self._lock.release()
+	# --- end of generate_metadata (...) ---
 
-	def _flist ( self ):
-		files = list()
-		if not self._metadata is None:
-			files.append ( self._metadata.filename )
-
-		for ver in self._packages:
-			files.append ( "%s-%s.ebuild" % ( self.name, ver ) )
-
-		return files
-	# --- end of _flist (...) ---
-
-	def ls ( self ):
-		return frozenset ( self._flist() )
-	# --- end of ls (...) ---
+	def generate_manifest ( self ):
+		"""Generates the Manifest file for this package.
 
-	def lslong ( self ):
-		return frozenset ( ( os.path.join (
-			'??' if self.physical_location is None else self.physical_location,
-			f
-		) for f in self._flist() ) )
-	# --- end of lslong (...) ---
+		expects: called in self.write(), after writing metadata/ebuilds
 
-	def __str__ ( self ): return '\n'.join ( self.ls() )
+		returns: None (implicit)
 
+		raises: !! TODO
+		* Exception if not physical
+		"""
+		if self.physical_location is None:
+			raise Exception ( "no directory assigned." )
+
+		# it should be sufficient to call create_manifest for one ebuild,
+		#  choosing the latest one here that exists in self.physical_location.
+		#
+		# metadata.xml's full path cannot be used for manifest creation here
+		#  'cause DISTDIR would be unknown
+		#
+		pkg_info_for_manifest = _latest_package (
+			pkg_filter=lambda pkg : not pkg ['ebuild_filepath'] is None,
+			use_lock=True
+		)
 
+		if pkg_info_for_manifest is None:
+			# ? FIXME
+			raise Exception (
+				"No ebuild written so far! I really don't know what do to!"
+			)
+		else:
+			# TODO: manifest creation interface is single threaded,
+			#        may want to 'fix' this later
+			manifest.create_manifest ( pkg_info_for_manifest, nofail=False )
 
+	# --- end of generate_manifest (...) ---

diff --git a/roverlay/portage/packageinfo.py b/roverlay/packageinfo.py
similarity index 87%
rename from roverlay/portage/packageinfo.py
rename to roverlay/packageinfo.py
index 7ac4940..7a77ca0 100644
--- a/roverlay/portage/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -12,10 +12,12 @@ from roverlay import config, util
 LOGGER = logging.getLogger ( 'PackageInfo' )
 
 VIRTUAL_KEYS = dict (
-	DISTDIR      = frozenset ( [ 'distdir', 'pkg_distdir' ] ),
-	EBUILD_FILE  = frozenset ( [ 'ebuild_file', 'efile' ] ),
-	HAS_SUGGESTS = frozenset ( [ 'has_suggests', 'has_rsuggests' ] ),
-	SRC_URI      = frozenset ( [ 'src_uri', 'package_url', 'url' ] ),
+	DISTDIR         = frozenset ( ( 'distdir', 'pkg_distdir' ) ),
+	# removing this key
+	#EBUILD_FILE     = frozenset ( ( 'ebuild_file', 'efile' ) ),
+	HAS_SUGGESTS    = frozenset ( ( 'has_suggests', 'has_rsuggests' ) ),
+	SRC_URI         = frozenset ( ( 'src_uri', 'package_url', 'url' ) ),
+	ALWAYS_FALLBACK = frozenset ( ( 'ebuild_filepath' ) ),
 )
 
 
@@ -120,17 +122,9 @@ class PackageInfo ( object ):
 			elif 'origin' in self._info:
 				return util.get_distdir ( self._info ['origin'] )
 
-		elif key_low in VIRTUAL_KEYS ['EBUILD_FILE']:
-			return os.path.join (
-				config.get_or_fail ( [ 'OVERLAY', 'dir' ] ),
-				config.get_or_fail ( [ 'OVERLAY', 'category' ] ),
-				self ['ebuild_name'].partition ( '-' ) [0],
-				self ['ebuild_name'] + ".ebuild"
-			)
-
 		elif key_low in VIRTUAL_KEYS ['HAS_SUGGESTS']:
-			if key_low in self._info:
-				return self._info [key_low]
+			if 'has_suggests' in self._info:
+				return self._info ['has_suggests']
 
 			else:
 				return False
@@ -151,7 +145,7 @@ class PackageInfo ( object ):
 		elif key_low in self._info:
 			return self._info [key_low]
 
-		elif do_fallback:
+		elif do_fallback or key_low in VIRTUAL_KEYS ['ALWAYS_FALLBACK']:
 			return fallback_value
 		else:
 			raise KeyError ( key )
@@ -195,6 +189,16 @@ class PackageInfo ( object ):
 		if 'ebuild' in info:
 			self._use_ebuild ( info ['ebuild'] )
 
+		if 'desc_data' in info
+			self ['desc_data'] =  info ['desc_data']
+		elif 'desc' in info:
+			self ['desc_data'] = info ['desc']
+
+
+		if 'suggests' in info:
+			self ['has_suggests'] = info ['suggests']
+
+
 		self._update_lock.release()
 	# --- end of update (**kw) ---
 
@@ -239,7 +243,12 @@ class PackageInfo ( object ):
 		arguments:
 		* ebuild --
 		"""
+		self ['ebuild'] = ebuild
+		# set status to ready for overlay
+
+		# this does no longer work FIXME
 		self ['has_suggests'] =  ebuild.has_rsuggests
 		# todo move Ebuild funcs to here
 		self ['ebuild_dir']   = ebuild.suggest_dir_name()
 		self ['ebuild_name']  = ebuild.suggest_name()
+	# --- end of _use_ebuild (...) ---

diff --git a/roverlay/portage/__init__.py b/roverlay/portage/__init__.py
deleted file mode 100644
index e69de29..0000000

diff --git a/roverlay/portage/ebuildcreator.py b/roverlay/portage/ebuildcreator.py
deleted file mode 100644
index aee45e1..0000000
--- a/roverlay/portage/ebuildcreator.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# R Overlay -- ebuild creation, "master" module
-# Copyright 2006-2012 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-import time
-import logging
-import threading
-
-try:
-	import queue
-except ImportError:
-	# python2
-	import Queue as queue
-
-
-from roverlay                     import config
-from roverlay.depres              import depresolver
-from roverlay.depres.channels     import EbuildJobChannel
-from roverlay.portage.ebuildjob   import EbuildJob
-
-class EbuildCreator ( object ):
-
-	NUMTHREADS = config.get ( 'EBUILD.jobcount', 0 )
-
-	def __init__ ( self ):
-		"""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  = depresolver.DependencyResolver ()
-
-		self.ebuild_jobs      = queue.Queue()
-		self.ebuild_jobs_done = list()
-
-		self.runlock  = threading.Lock()
-		self._threads = None
-
-		self.logger = logging.getLogger ( 'EbuildCreator' )
-
-		# this topic to change FIXME/TODO
-		#  metadata [<ebuild_name>] = MetadataJob instance
-		self.metadata = dict()
-
-	# --- end of init (...) ---
-
-	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:
-		* package_file -- path R package file
-		"""
-		new_job = EbuildJob ( package_file, self.get_resolver_channel )
-
-		self.ebuild_jobs.put ( new_job )
-
-		return new_job
-
-	# --- end of add_package (...) ---
-
-	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, logger=logger )
-		)
-
-	# --- end of get_resolver_channel (...) ---
-
-	def close ( self ):
-		self.depresolve_main.close()
-	# --- end of close (...) ---
-
-	def _thread_run_ebuilds ( self ):
-
-		while not self.ebuild_jobs.empty():
-			try:
-				job = self.ebuild_jobs.get_nowait()
-			except queue.Empty:
-				# queue is empty, done
-				return
-
-			job.run()
-			self.ebuild_jobs_done.append ( job )
-
-	# --- end of _thread_run_ebuilds (...) ---
-
-	def start ( self ):
-		"""Tells all EbuildJobs to run."""
-
-		if not self.runlock.acquire ( False ):
-			# already running
-			return True
-
-		start = time.time()
-
-		jobcount = EbuildCreator.NUMTHREADS
-
-		if jobcount < 1:
-			( self.logger.warning if jobcount < 0 else self.logger.debug ) (
-				"Running in sequential mode."
-			)
-			self._thread_run_ebuilds()
-		else:
-			self.logger.warning (
-				"Running in concurrent mode with %i jobs." % jobcount
-			)
-			self._threads = [
-				threading.Thread ( target = self._thread_run_ebuilds )
-				for n in range ( jobcount )
-			]
-
-			for t in self._threads: t.start()
-			for t in self._threads: t.join()
-
-			del self._threads
-			self._threads = None
-
-
-		stop = time.time()
-		self.logger.info ( 'done after %f seconds' % ( stop - start ) )
-
-		# make metadata, topic to change... FIXME/TODO
-		for ejob in self.ebuild_jobs_done:
-			if ejob.get_ebuild() is None: continue
-
-			edir = ejob.package_info ['ebuild_dir']
-			if not edir in self.metadata:
-				self.metadata [edir] = ejob.feed_metadata ( create=True )
-			else:
-				ejob.feed_metadata ( metadata=self.metadata [edir] )
-
-		self.runlock.release()
-
-	# --- end of start (...) ---
-
-	def collect_ebuilds ( self ):
-		"""Returns all ebuilds. (They may not be ready / TODO)"""
-		ebuilds = [ job.get_ebuild() for job in self.ebuild_jobs_done ]
-		return filter ( None, ebuilds )
-
-	# --- 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.
-		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:
-		* 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 self.ebuild_headers:
-			# previously read
-			return self.ebuild_headers [ebuild_header_file]
-
-		else:
-			# read file
-			try:
-				fh = open ( ebuild_header_file, 'r' )
-				lines = fh.readlines()
-				fh.close()
-				self.ebuild_headers [ebuild_header_file] = lines
-				del fh
-				return lines
-
-			except IOError as err:
-				# todo
-				raise
-
-	# --- end of get_ebuild_header (...) ---

diff --git a/roverlay/portage/ebuildjob.py b/roverlay/portage/ebuildjob.py
deleted file mode 100644
index 6ad2738..0000000
--- a/roverlay/portage/ebuildjob.py
+++ /dev/null
@@ -1,333 +0,0 @@
-# R Overlay -- ebuild creation, "job" module
-# Copyright 2006-2012 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-import logging
-import re
-
-from roverlay                            import config, util
-from roverlay.portage.ebuild             import Ebuild
-from roverlay.portage.packageinfo        import PackageInfo
-from roverlay.portage.metadata.creation  import MetadataJob
-from roverlay.rpackage.descriptionreader import DescriptionReader
-
-
-class EbuildJob ( object ):
-	LOGGER = logging.getLogger ( 'EbuildJob' )
-
-	DEFAULT_EBUILD_HEADER = config.get ( 'EBUILD.default_header' )
-
-	# 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         = [],
-	)
-
-	def __init__ ( self, package_file, depres_channel_spawner=None ):
-		"""Initializes an EbuildJob, which creates an ebuild for an R package.
-
-		arguments:
-		* package_info -- R package file info
-		* 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_info = PackageInfo ( filepath=package_file )
-		self.package_info.set_readonly()
-
-		try:
-			self.logger = EbuildJob.LOGGER.getChild (
-				self.package_info ['filename']
-			)
-		except KeyError:
-			self.logger = EbuildJob.LOGGER.getChild ( '__undef__' )
-
-		self.description_reader = DescriptionReader (
-			self.package_info, logger=self.logger
-		)
-
-		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 feed_metadata ( self, create=False, metadata=None ):
-		"""Feeds metadata, either a existing MetadataJob instance or a new one.
-
-		arguments:
-		* create   -- if True: create new metadata, "function mode",
-		               requires bool (metadata) == False
-		* metadata -- if not None: metadata to update, "method mode",
-		               requires bool (create) == False
-
-		returns: created metadata if in function mode (create is True) else
-		         None (implicit)
-
-		raises: Exception if (create <=> metadata)
-		"""
-		if not create and not metadata:
-			raise Exception ( "either create or metadata" )
-		elif create and metadata:
-			raise Exception ( "either create or metadata" )
-		elif create:
-			metadata = MetadataJob (
-				self.package_info,
-				self.logger.getChild ( 'metadata' )
-			)
-
-
-		metadata.update (
-			self.description_reader.get_desc ( run_if_unset=False ),
-			self.package_info
-		)
-
-		if create: return metadata
-	# --- end of feed_metadata (...) ---
-
-	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.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 (should be?) guaranteed that self.ebuild is None unless the Ebuild is successfully created##
-		"""
-		return self.ebuild
-
-	# --- end of get_ebuild (...) ---
-
-	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.
-
-		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 (...) ---
-
-	def done_success ( self ):
-		"""Returns True if this has been successfully finished."""
-		return self.get_status ( 'SUCCESS' )
-
-	# --- 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 and creates an Ebuild object that is ready
-		to be written into a file.
-		"""
-
-		# TODO move hardcoded entries to config/const
-
-		try:
-			# enforcing BRANCHMAP status control: set status or return
-			if not self._set_status ( 'BUSY', True ): return
-
-			desc = self.description_reader.get_desc ( True )
-			if desc is None:
-				self._set_status ( 'FAIL' )
-				self.logger.info ( 'Cannot create an ebuild for this package.' )
-
-
-			ebuild = Ebuild ( self.logger.getChild ( "Ebuild" ) )
-
-			ebuild.add ( 'pkg_name', self.package_info ['package_name'] )
-
-			# TODO move regex to config/const
-			ebuild.add (
-				'pkg_version',
-				re.sub ( '[-]{1,}', '.', self.package_info ['package_version'] )
-			)
-			ebuild.add ( 'PKG_FILE', self.package_info ['package_file'] )
-
-
-			have_description = False
-
-			if 'Title' in desc:
-				ebuild.add ( 'DESCRIPTION', desc ['Title'] )
-				have_description = True
-
-			if 'Description' in desc:
-				ebuild.add (
-					'DESCRIPTION',
-					( '// ' if have_description else '' ) + desc ['Description']
-				)
-
-			del have_description
-
-
-			ebuild.add ( 'SRC_URI', self.package_info ['package_url'] )
-
-			## default ebuild header, could use some const here (eclass name,..)
-			# TODO use a single string as ebuild header instead of joining it
-			#      for every ebuild
-			ebuild.add (
-				'ebuild_header',
-				EbuildJob.DEFAULT_EBUILD_HEADER,
-				False
-			)
-
-			if not self.request_resolver is None:
-				# dependency resolution is enabled
-
-				dep_type = desc_field = None
-
-
-				for dep_type in EbuildJob.DEPENDENCY_FIELDS:
-
-					resolver = None
-
-					for desc_field in EbuildJob.DEPENDENCY_FIELDS [dep_type]:
-
-						if desc_field in desc:
-							if not resolver:
-								resolver = self.get_resolver ( dep_type )
-
-							if isinstance ( desc [desc_field], list ):
-								resolver.add_dependencies ( desc [desc_field] )
-
-							else:
-								resolver.add_depency ( desc [desc_field] )
-
-
-				# lazy depres: wait until done and stop if any resolver channel
-				# returns None (which implies failure)
-				# wait for depres and store results
-				resolved = True
-
-				if not self._set_status ( 'WAIT_RESOLVE' ): return
-
-				for resolver in self._depres.values():
-					if resolver.satisfy_request() is None:
-						resolved = False
-						break
-
-				if not self._set_status ( 'BUSY' ): return
-
-				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 () )
-						)
-
-						if deplist is None:
-							## 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", deplist, dep_type )
-							ebuild.add ( dep_type, deplist, False )
-
-						else:
-							raise Exception (
-								"dep_resolver is broken: list or set expected!"
-							)
-					# --- end for
-
-					# tell the dep resolver channels that we're done
-					for r in self._depres.values(): r.close ()
-
-			# --- end dep resolution
-
-
-			## finalize self.ebuild: forced text creation + make it readonly
-			if ebuild.prepare ( True, True ):
-				self.ebuild = ebuild
-
-				# update package info
-				self.package_info.set_writeable()
-				self.package_info.update ( ebuild=ebuild )
-				self.package_info.set_readonly()
-
-
-
-		except Exception as e:
-			# any exception means failure
-			self._set_status ( 'FAIL' )
-			self.logger.exception ( e )
-			raise
-
-	# --- end of run (...) ---
-
-	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.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/portage/metadata/__init__.py b/roverlay/portage/metadata/__init__.py
deleted file mode 100644
index e69de29..0000000

diff --git a/roverlay/portage/overlay/__init__.py b/roverlay/portage/overlay/__init__.py
deleted file mode 100644
index e69de29..0000000

diff --git a/roverlay/static/__init__.py b/roverlay/static/__init__.py
new file mode 100644
index 0000000..13e7869
--- /dev/null
+++ b/roverlay/static/__init__.py
@@ -0,0 +1,5 @@
+# R Overlay -- not signleton but static access to certain objects
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# currently used for testing

diff --git a/roverlay/static/depres.py b/roverlay/static/depres.py
new file mode 100644
index 0000000..a351f51
--- /dev/null
+++ b/roverlay/static/depres.py
@@ -0,0 +1,29 @@
+# R Overlay -- dependency resolution, static resolver access
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from roverlay.depres.channels    import EbuildJobChannel
+from roverlay.depres.depresolver import DependencyResolver
+
+_RESOLVER = None
+
+def resolver():
+	"""Returns the resolver."""
+	global _RESOLVER
+	if _RESOLVER is None:
+		_RESOLVER = DependencyResolver()
+	return _RESOLVER
+# --- end of resolver (...) ---
+
+def get_ebuild_channel ( name=None, logger=None ):
+	"""Returns a communication channel to the dependency resolver.
+
+	arguments:
+	name --
+	logger --
+	"""
+	return resolver().register_channel (
+		EbuildJobChannel ( name=name, logger=logger )
+	)
+
+# --- end of get_resolver_channel (...) ---



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2012-06-19 18:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-19 18:19 [gentoo-commits] proj/R_overlay:master commit in: roverlay/portage/metadata/, roverlay/static/, roverlay/, André Erdmann

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