umbra.managers.patchesManager — Umbra 1.0.4 documentation

### Navigation

- index
- modules |
- Umbra 1.0.4 documentation »
- Module code »

# Source code for umbra.managers.patchesManager

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    """
    **patchesManager.py**

    **Platform:**
    	Windows, Linux, Mac Os X.

    **Description:**
    	This module defines the :class:`PatchesManager` and :class:`Patches` classes.

    **Others:**

    """

    #**********************************************************************************************************************
    #***	External imports.
    #**********************************************************************************************************************
    import os
    import sys

    #**********************************************************************************************************************
    #***	Internal imports.
    #**********************************************************************************************************************
    import foundations.common
    import foundations.dataStructures
    import foundations.exceptions
    import foundations.strings
    import foundations.verbose
    import foundations.walkers
    import umbra.exceptions
    from foundations.io import File

    #**********************************************************************************************************************
    #***	Module attributes.
    #**********************************************************************************************************************
    __author__ = "Thomas Mansencal"
    __copyright__ = "Copyright (C) 2008 - 2012 - Thomas Mansencal"
    __license__ = "GPL V3.0 - http://www.gnu.org/licenses/"
    __maintainer__ = "Thomas Mansencal"
    __email__ = "thomas.mansencal@gmail.com"
    __status__ = "Production"

    __all__ = ["LOGGER", "Patch", "PatchesManager"]

    LOGGER = foundations.verbose.installLogger()

    #**********************************************************************************************************************
    #***	Module classes and definitions.
    #**********************************************************************************************************************
    class Patch(foundations.dataStructures.Structure):
    	"""
    	This class represents a storage object for :class:`PatchesManager` class patch.
    	"""

    	def __init__(self, **kwargs):
    		"""
    		.. Sphinx: Statements updated for auto-documentation purpose.

    		:param \*\*kwargs: name, path, module, apply, uid. ( Key / Value pairs )
    		"""

    		LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))

    		foundations.dataStructures.Structure.__init__(self, **kwargs)

    class PatchesManager(object):
    	"""
    	This class defines the Application patches manager.
    	"""

    	def __init__(self, historyFile=None, paths=None, extension="py"):
    		"""
    		.. Sphinx: Statements updated for auto-documentation purpose.

    		:param historyFile: Patches history file. ( String )
    		:param paths: Patches paths. ( Tuple / List )
    		:param extension: Patches extension. ( String )
    		"""

    		LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))

    		# --- Setting class attributes. ---
    		self.__historyFile = None
    		self.historyFile = historyFile
    		self.__paths = None
    		self.paths = paths
    		self.__extension = None
    		self.extension = extension

    		if foundations.common.pathExists(self.__historyFile) is False:
    			open(self.__historyFile, "w").close()

    		self.__patches = {}

    	#******************************************************************************************************************
    	#***	Attributes properties.
    	#******************************************************************************************************************
    	@property
    	def historyFile(self):
    		"""
    		This method is the property for **self.__historyFile** attribute.

    		:return: self.__historyFile. ( String )
    		"""

    		return self.__historyFile

    	@historyFile.setter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(AssertionError)
    	def historyFile(self, value):
    		"""
    		This method is the setter method for **self.__historyFile** attribute.

    		:param value: Attribute value. ( String )
    		"""

    		if value is not None:
    			assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format(
    			"historyFile", value)
    		self.__historyFile = value

    	@historyFile.deleter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
    	def historyFile(self):
    		"""
    		This method is the deleter method for **self.__historyFile** attribute.
    		"""

    		raise foundations.exceptions.ProgrammingError(
    		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "historyFile"))

    	@property
    	def paths(self):
    		"""
    		This method is the property for **self.__paths** attribute.

    		:return: self.__paths. ( Tuple / List )
    		"""

    		return self.__paths

    	@paths.setter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(AssertionError)
    	def paths(self, value):
    		"""
    		This method is the setter method for **self.__paths** attribute.

    		:param value: Attribute value. ( Tuple / List )
    		"""

    		if value is not None:
    			assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
    			"paths", value)
    			for element in value:
    				assert type(element) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format(
    				"paths", element)
    				assert os.path.exists(element), "'{0}' attribute: '{1}' directory doesn't exists!".format("paths", element)
    		self.__paths = value

    	@paths.deleter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
    	def paths(self):
    		"""
    		This method is the deleter method for **self.__paths** attribute.
    		"""

    		raise foundations.exceptions.ProgrammingError(
    		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "paths"))

    	@property
    	def extension(self):
    		"""
    		This method is the property for **self.__extension** attribute.

    		:return: self.__extension. ( String )
    		"""

    		return self.__extension

    	@extension.setter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(AssertionError)
    	def extension(self, value):
    		"""
    		This method is the setter method for **self.__extension** attribute.

    		:param value: Attribute value. ( String )
    		"""

    		if value is not None:
    			assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format(
    			"extension", value)
    		self.__extension = value

    	@extension.deleter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
    	def extension(self):
    		"""
    		This method is the deleter method for **self.__extension** attribute.
    		"""

    		raise foundations.exceptions.ProgrammingError(
    		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "extension"))

    	@property
    	def patches(self):
    		"""
    		This method is the property for **self.__patches** attribute.

    		:return: self.__patches. ( Dictionary )
    		"""

    		return self.__patches

    	@patches.setter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
    	def patches(self, value):
    		"""
    		This method is the setter method for **self.__patches** attribute.

    		:param value: Attribute value. ( Dictionary )
    		"""

    		raise foundations.exceptions.ProgrammingError(
    		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "patches"))

    	@patches.deleter
    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
    	def patches(self):
    		"""
    		This method is the deleter method for **self.__patches** attribute.
    		"""

    		raise foundations.exceptions.ProgrammingError(
    		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "patches"))

    	#******************************************************************************************************************
    	#***	Class methods.
    	#******************************************************************************************************************
    	def __getitem__(self, patch):
    		"""
    		This method reimplements the :meth:`object.__getitem__` method.

    		:param patch: Patch name. ( String )
    		:return: Patch. ( Patch )
    		"""

    		return self.__patches.__getitem__(patch)

    	def __iter__(self):
    		"""
    		This method reimplements the :meth:`object.__iter__` method.

    		:return: Patchs iterator. ( Object )
    		"""

    		return self.__patches.iteritems()

    	def __contains__(self, patch):
    		"""
    		This method reimplements the :meth:`object.__contains__` method.

    		:param patch: Patch name. ( String )
    		:return: Patch existence. ( Boolean )
    		"""

    		return patch in self.__patches.keys()

    	def __len__(self):
    		"""
    		This method reimplements the :meth:`object.__len__` method.

    		:return: Patchs count. ( Integer )
    		"""

    		return len(self.__patches.keys())

    	def listPatches(self):
    		"""
    		This method returns the registered patches.

    		:return: Patches list. ( List )
    		"""

    		return sorted(self.__patches.keys())

    	def isPatchRegistered(self, patch):
    		"""
    		This method returns if the given patch is registered.

    		:param patch: Patch. ( String )
    		:return: Is patch registered. ( Boolean )
    		"""

    		return patch in self

    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(umbra.exceptions.PatchInterfaceError)
    	def registerPatch(self, name, path):
    		"""
    		This method registers given patch.

    		:param name: Patch name. ( String )
    		:param path: Patch path. ( String )
    		:return: Method success. ( Boolean )
    		"""

    		patch = foundations.strings.getSplitextBasename(path)
    		LOGGER.debug("> Current patch: '{0}'.".format(patch))

    		directory = os.path.dirname(path)
    		not directory in sys.path and sys.path.append(directory)

    		module = __import__(patch)
    		if hasattr(module, "apply") and hasattr(module, "UID"):
    			self.__patches[name] = Patch(name=name,
    										path=path,
    										module=module,
    										apply=getattr(module, "apply"),
    										uid=getattr(module, "UID"))
    		else:
    			raise umbra.exceptions.PatchInterfaceError(
    			"{0} | '{1}' is not a valid patch and has been rejected!".format(self.__class__.__name__, patch))
    		return True

    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(umbra.exceptions.PatchRegistrationError)
    	def registerPatches(self):
    		"""
    		This method registers the patches.

    		:return: Method success. ( Boolean )
    		"""

    		if not self.__paths:
    			return False

    		unregisteredPatches = []
    		for path in self.paths:
    			for file in foundations.walkers.filesWalker(path, ("\.{0}$".format(self.__extension),), ("\._",)):
    				name = foundations.strings.getSplitextBasename(file)
    				if not self.registerPatch(name, file):
    					unregisteredPatches.append(name)

    		if not unregisteredPatches:
    			return True
    		else:
    			raise umbra.exceptions.PatchRegistrationError(
    			"{0} | '{1}' patches failed to register!".format(self.__class__.__name__,
    																", ".join(unregisteredPatches)))

    	#***	Sphinx: Decorator commented for auto-documentation purpose. 	@foundations.exceptions.handleExceptions(umbra.exceptions.PatchApplyError)
    	def applyPatch(self, patch):
    		"""
    		This method applies given patch.

    		:param patch: Patch. ( Patch )
    		:return: Method success. ( Boolean )
    		"""

    		historyFile = File(self.__historyFile)
    		patchesHistory = historyFile.cache() and [line.strip() for line in historyFile.content] or []

    		if patch.uid not in patchesHistory:
    			LOGGER.debug("> Applying '{0}' patch!".format(patch.name))
    			if patch.apply():
    				historyFile.content = ["{0}\n".format(patch.uid)]
    				historyFile.append()
    			else:
    				raise umbra.exceptions.PatchApplyError("{0} | '{1}' patch failed to apply!".format(
    				self.__class__.__name__, patch.path))
    		else:
    			LOGGER.debug("> '{0}' patch is already applied!".format(patch.name))
    		return True

    	def applyPatches(self):
    		"""
    		This method applies the patches.

    		:return: Method success. ( Boolean )
    		"""

    		success = True
    		for name, patch in sorted(self):
    			success = self.applyPatch(patch)
    		return success

    	def getPatchFromUid(self, uid):
    		"""
    		This method returns the patch with given uid.

    		:param uid: Patch uid. ( String )
    		:return: Patch. ( Patch )
    		"""

    		for name, patch in self:
    			if patch.uid == uid:
    				return patch

### Navigation

- index
- modules |
- Umbra 1.0.4 documentation »
- Module code »