aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'roverlay/overlay/__init__.py')
-rw-r--r--roverlay/overlay/__init__.py306
1 files changed, 306 insertions, 0 deletions
diff --git a/roverlay/overlay/__init__.py b/roverlay/overlay/__init__.py
new file mode 100644
index 0000000..081f0b8
--- /dev/null
+++ b/roverlay/overlay/__init__.py
@@ -0,0 +1,306 @@
+# R Overlay -- <comment TODO>
+# Copyright 2006-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import threading
+import logging
+import shutil
+import os
+
+from roverlay import config, util
+
+from roverlay.overlay.category import Category
+
+DEFAULT_USE_DESC = '\n'.join ( [
+ 'byte-compile - enable byte compiling',
+ 'R_suggests - install recommended packages'
+] )
+
+class Overlay ( object ):
+
+ def __init__ (
+ self,
+ name=None,
+ logger=None,
+ directory=None,
+ default_category=None,
+ eclass_files=None
+ ):
+
+ # not setting any default values here (currently)
+
+ if name is None:
+ self.name = config.get_or_fail ( 'OVERLAY.name' )
+ else:
+ self.name = name
+
+ if logger is None:
+ #self.logger = logging.getLogger ( self.name )
+ self.logger = logging.getLogger ( 'overlay' )
+ else:
+ #self.logger = logger.getChild ( self.name )
+ self.logger = logger.getChild ( 'overlay' )
+
+ if directory is None:
+ self.physical_location = config.get_or_fail ( 'OVERLAY.dir' )
+ else:
+ self.physical_location = directory
+
+ if default_category is None:
+ self.default_category = config.get_or_fail ( 'OVERLAY.category' )
+ else:
+ self.default_category = default_category
+
+ self.eclass_files = eclass_files
+
+ #
+ self._profiles_dir = os.path.join ( self.physical_location, 'profiles' )
+
+ self._catlock = threading.Lock()
+ self._categories = dict()
+ # --- end of __init__ (...) ---
+
+ def _get_category ( self, category ):
+ """Returns a reference to the given category. Creates it if necessary.
+
+ arguments:
+ * category -- category identifier as string
+ """
+ if not category in self._categories:
+ self._catlock.acquire()
+ if not category in self._categories:
+ self._categories [category] = Category (
+ category,
+ self.logger,
+ None if self.physical_location is None else \
+ os.path.join ( self.physical_location, category )
+ )
+ self._catlock.release()
+
+ return self._categories [category]
+ # --- end of _get_category (...) ---
+
+ def add ( self, package_info, category=None ):
+ """Adds a package to this overlay.
+
+ arguments:
+ * package_info -- PackageInfo of the package to add
+ * category -- category where the pkg should be put in, defaults to
+ self.default_category
+
+ returns: None (implicit)
+ """
+ self._get_category (
+ self.default_category if category is None else category
+ ) . add ( package_info )
+ # --- end of add (...) ---
+
+ def show ( self, **show_kw ):
+ """Presents the ebuilds/metadata stored in this overlay.
+
+ arguments:
+ * **show_kw -- keywords for package.PackageDir.show(...)
+
+ returns: None (implicit)
+ """
+ for cat in self._categories.values(): cat.show ( **show_kw )
+ # --- end of show (...) ---
+
+ def write ( self, **write_kw ):
+ """Writes the overlay to its physical location (filesystem), including
+ metadata and Manifest files.
+ TODO include Manifest generation in package.py
+
+ arguments:
+ * **write_kw -- keywords for package.PackageDir.write(...)
+
+ returns: None (implicit)
+
+ raises: !! TODO
+
+ TODO/FIXME/DOC: This is not thread-safe, it's expected to be called
+ when ebuild creation is done.
+ """
+ # writing profiles/ here, rewriting categories/ later
+ self._init_overlay ( reimport_eclass=True, make_profiles_dir=True )
+
+ for cat in self._categories.values():
+ if cat.physical_location and not cat.empty():
+ util.dodir ( cat.physical_location )
+ cat.write()
+
+ self._write_categories ( only_active=True )
+ # --- end of write (...) ---
+
+ def write_incremental ( self, **write_kw ):
+ """Writes all ebuilds that have been added since the last
+ write_incremental call.
+ TODO:
+ * This could be useful to save some mem by removing already written
+ package infos.
+ * This has to be thread safe
+ """
+ raise Exception ( "method stub" )
+ # --- end of write_incremental (...) ---
+
+ def generate_metadata ( self, **metadata_kw ):
+ """Tells the overlay's categories to create metadata.
+ You don't have to call this before write()/show() unless you want to use
+ special metadata options.
+
+ arguments:
+ * **metadata_kw -- keywords for package.PackageDir.generate_metadata(...)
+
+ returns: None (implicit)
+ """
+ for cat in self._categories.values():
+ 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.
+
+ arguments:
+ * only_active_categories -- if True: do not list categories without
+ ebuilds in profiles/categories
+ """
+ # profiles/
+ util.dodir ( self._profiles_dir )
+ self._write_repo_name()
+ self._write_categories ( only_active=only_active_categories )
+ self._write_usedesc()
+ # --- end of _write_profiles_dir (...) ---
+
+ def _write_profiles_file ( self, filename, to_write ):
+ """Writes a file in profiles/.
+
+ arguments:
+ * filename -- name of the file to write (including file extension)
+ * to_write -- string to write (don't forget newline at the end)
+ """
+ fh = None
+ try:
+ fh = open ( os.path.join ( self._profiles_dir, filename ), 'w' )
+ if to_write:
+ # else touch file
+ fh.write ( to_write )
+ except IOError as e:
+ self.logger.exception ( e )
+ raise
+ finally:
+ if fh: fh.close()
+ # --- end of _write_profiles_file (...) ---
+
+ def _write_repo_name ( self ):
+ """Writes profiles/repo_name."""
+ self._write_profiles_file ( 'repo_name', self.name + '\n' )
+ # --- end of _write_repo_name (...) ---
+
+ def _write_categories ( self, only_active=True ):
+ """Writes profiles/categories.
+
+ arguments:
+ * only_active -- exclude categories without ebuilds
+ """
+ cats = None
+ if only_active:
+ cats = [
+ name for name, category
+ in self._categories.items() if not category.empty()
+ ]
+ else:
+ cats = list ( self._categories.keys() )
+
+ if cats:
+ self._write_profiles_file (
+ 'categories',
+ '\n'.join ( cats ) + '\n'
+ )
+ # --- end of _write_categories (...) ---
+
+ def _write_usedesc ( self ):
+ """Writes profiles/use.desc."""
+ # TODO: config entry
+ use_desc = config.get (
+ 'OVERLAY.use_desc',
+ fallback_value=DEFAULT_USE_DESC
+ )
+ if use_desc:
+ self._write_profiles_file ( 'use.desc', use_desc + '\n' )
+ # --- end of _write_usedesc (...) ---
+
+ def _init_overlay ( self, reimport_eclass=False, make_profiles_dir=False ):
+ """Initializes the overlay at its physical/filesystem location.
+
+ arguments:
+ * reimport_eclass -- whether to copy existing eclass files
+ again (True) or not
+ * make_profiles_dir -- if True: create the profiles/ dir now
+
+ raises:
+ * Exception if no physical location assigned
+ * <TODO> passes IOError,...
+ """
+ if self.physical_location is None:
+ raise Exception ( "no directory assigned." )
+
+ try:
+ root = self.physical_location
+ # mkdir overlay root
+ os.makedirs ( root, exist_ok=True ) # raises?
+
+ if self.eclass_files:
+ # import eclass files
+ eclass_dir = os.path.join ( root, 'eclass' )
+ try:
+ util.dodir ( eclass_dir )
+
+ for eclass in self.eclass_files:
+ src = eclass
+ dest = None
+ if isinstance ( eclass, str ):
+ dest = os.path.basename ( eclass )
+ else:
+ # list-like specification ( src, destname )
+ src = eclass [0]
+ dest = eclass [1]
+
+ if reimport_eclass or not os.path.isfile ( dest ):
+ shutil.copyfile ( src, dest )
+
+
+ except Exception as e:
+ #self.logger.exception ( e ) TODO try-catch blocks
+ self.logger.critical ( "Cannot import eclass files!" )
+ raise
+
+ # -- eclass
+ if make_profiles_dir:
+ self._write_profiles_dir ( only_active_categories=False )
+
+ except IOError as e:
+
+ self.logger.exception ( e )
+ self.logger.critical ( "^failed to init overlay" )
+ raise
+
+
+
+
+
+
+