diff options
Diffstat (limited to 'roverlay/overlay/__init__.py')
-rw-r--r-- | roverlay/overlay/__init__.py | 306 |
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 + + + + + + + |