# Copyright 2015 VMware, Inc.  All rights reserved. -- VMware Confidential
#
'''
Script responsible to execute a component patching hook in current python process
'''

import sys
import os
import logging
import imp

from patch_errors import BaseError, InternalError, ComponentError
from reporting import getProgressReporter
from vmware.patching.utils.reporting_utils import configureReportingFactory
from extensions import Hook

logger = logging.getLogger(__name__)

def executeHook(patchModulePath, hook, args, reportQueue):
    '''Executes a component patch hook in current python process.

    @param patchModulePath: Python module where component patching hooks are defined at
    @type patchModulePath: str

    @param hook: The patching hook which has to be executed. Allowed values are
      defined at extensions.Hook structure.
    @type hook: str

    @param args: The patching hooks input. The object will be passed to the
      the component patching hook.
    @type args: Serializable

    @param reportQueue: A queue to be used for reporting purposes by the patching
        hook
    @type reportQueue: multiprocessor.Queue

    @return: The result of the patching hook
    @rtype: Serializable

    @raise: patch_errors.ComponentError: If the component fails to be executed in
      the provided contract.
    '''
    modulePath, moduleName = os.path.split(patchModulePath)

    logger.debug("Add component folder %s to python path", modulePath)
    sys.path.append(modulePath)

    try:
        # Test if the component script is defined/deployed on the system.
        imp.find_module(moduleName)
    except ImportError:
        logger.exception("Component's script '%s' is not regular python "
                "module", moduleName)
        raise

    shouldReportErrors = hook!=Hook.OnSuccess
    identifier = "%s:%s" % (os.path.basename(patchModulePath), hook)
    configureReportingFactory(identifier, reportQueue, reportErrors=shouldReportErrors)
    getProgressReporter().updateProgress(0)
    try:
        # Import dynamically the module containing the component upgrade script
        # If a module adds newer python modules, then this could lead to module
        # duplication. It's better to execute the module in a separate process
        module = __import__(moduleName, globals(), locals())

        # Discover and invoke the extension
        from extensions import Extension
        systemExtension = Extension(module, hook)
        executionResult = systemExtension(args)

        getProgressReporter().success()
        return executionResult
    except BaseError as baseError:
        logger.exception("Patch hook '%s:%s' failed.", moduleName, hook)
        raise ComponentError(baseError, identifier)
    except Exception as e:
        logger.exception("Patch hook '%s:%s' failed.", moduleName, hook)
        # Wrap the error in InternalError
        raise ComponentError(InternalError(str(e)), identifier)