示例#1
0
    def __init__(self, propagate=1, override=None, excepts=False):
        """
        Constructor.
        
        :param propagate: If this evaluates to false, logging messages are not 
                          passed by this logger or by child loggers to higher 
                          level (ancestor) loggers.
        :type propagate: boolean
        
        :param override: Overrides the default log level for the intern logger.
        :type override: NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL
        """

        Validator.__init__(self)

        self.check_regex = re.compile(constants.CHECK_REGEX)
        self.handler_regex = re.compile(constants.HANDLER_REGEX)

        self.default_profile = False
        self.main = None
        self.errors = 0
        self.excepts = excepts

        self.valid_checks = []
        self.valid_handlers = []

        self.logger = LoggerFactory().create(self.__module__, propagate,
                                             override)

        self.check_manager = CheckManager()
        self.handler_manager = HandlerManager()
示例#2
0
    def __init__(self, hook, repository_path):
        """
        Constructor.
        
        :param hook: The hook that has to be executed. Valid values are 
                     constants.PRECOMMIT or constants.POSTCOMMIT.
        :type hook: constants.PRECOMMIT, constants.POSTCOMMIT.
        :param repository_path: The path to the current repository.
        :type repository_path: string
        """

        self.hook = hook
        self.repository_path = repository_path

        self.checks = CheckManager()
        self.handlers = HandlerManager()
        self.result = constants.SUCCESS
        self.main = None
        self.transaction = None

        self.logger = LoggerFactory().create(self.__module__)
示例#3
0
    def __init__(self, hook, repository_path):
        """
        Constructor.
        
        :param hook: The hook that has to be executed. Valid values are 
                     constants.PRECOMMIT or constants.POSTCOMMIT.
        :type hook: constants.PRECOMMIT, constants.POSTCOMMIT.
        :param repository_path: The path to the current repository.
        :type repository_path: string
        """
        
        self.hook = hook
        self.repository_path = repository_path

        self.checks = CheckManager()
        self.handlers = HandlerManager()
        self.result = constants.SUCCESS
        self.main = None
        self.transaction = None
        
        self.logger = LoggerFactory().create(self.__module__)
示例#4
0
class RepoGuard(object):
    """
    Main RepoGuard class.
    """
    
    def __init__(self, hook, repository_path):
        """
        Constructor.
        
        :param hook: The hook that has to be executed. Valid values are 
                     constants.PRECOMMIT or constants.POSTCOMMIT.
        :type hook: constants.PRECOMMIT, constants.POSTCOMMIT.
        :param repository_path: The path to the current repository.
        :type repository_path: string
        """
        
        self.hook = hook
        self.repository_path = repository_path

        self.checks = CheckManager()
        self.handlers = HandlerManager()
        self.result = constants.SUCCESS
        self.main = None
        self.transaction = None
        
        self.logger = LoggerFactory().create(self.__module__)
        
    def load_transaction(self, name):
        """
        Load the transaction with the given name.
        
        :param name: The name of the current transaction.
        :type name: string
        """
        
        self.transaction = Transaction(self.repository_path, name)
        
    def load_config(self, tpl_dirs, config):
        """
        Load the project configuration.
        
        :param tpl_dirs: Path lists where all templates are located.
        :type tpl_dirs: string
                            
        :param config: The path or a splittedline project configuration string.
        :type config: string
        """
        
        self.logger.debug("Loading project configuration...")
        hooks_path = os.path.join(self.repository_path, "hooks")
        self.main = ProjectConfig(config, hooks_path, tpl_dirs)
        self.logger.debug("Project configuration loaded.")
        
    def validate(self):
        """
        Runs the internal validation process of the current loaded 
        configuration.
        
        :return: Returns the status code of the validator. succes = 0, error > 0
        :rtype: integer
        """
        
        validator = ConfigValidator(excepts=True)
        return validator.validate(self.main)
    
    def _combined_profile_regexes(self):
        """
        Returns a regular expression string which matches all 
        files that are covered by any special profile. A special
        profile defines a non-empty regex parameter.
        """
        
        combined_profile_regexes = ""
        for profile in self.main.profiles:
            if not profile.regex is None:
                combined_profile_regexes += "(%s)|" % profile.regex
        if not combined_profile_regexes:
            combined_profile_regexes = None
        else:
            combined_profile_regexes = combined_profile_regexes[:-1]
        return combined_profile_regexes   
    
    def run(self):
        """
        Execution of the checking _process and handler handling.
        It is recommended to call the load_config method before 
        calling this method.
        
        :return: Returns the _process result as a constant string.
        :rtype: constants.SUCCESS, constants.ERROR
        """
        
        try:
            self.logger.debug("Running run...")
            combined_profile_regexes = self._combined_profile_regexes()
            self.logger.debug("Default ignore regex: %s", combined_profile_regexes)
            
            # Process executing
            for profile in self.main.profiles:
                ignores = list()
                if not profile.regex is None:
                    self.transaction.profile = profile.regex
                else: 
                    # default profile: covers all files
                    # which are not handled by a special profile
                    self.transaction.profile = ".*"
                    if not combined_profile_regexes is None:
                        ignores = [combined_profile_regexes]
                    
                # if there are no files in this profile continue.
                if not self.transaction.get_files(ignore_list=ignores):
                    self.logger.debug("Profile '%s' skipped.", profile.name)
                    continue
                self._run_profile(profile)
                
            self.logger.debug("Run finished with %s.", self.result)
            return self.result
        finally:
            self.logger.debug("Cleaning up transaction.")
            self.transaction.cleanup()

    def run_profile(self, name):
        """ Runs a specific profile. """
        
        try:
            profile_found = False
            for profile in self.main.profiles:
                if name == profile.name:
                    self._run_profile(profile)
                    profile_found = True
                    
            if not profile_found:
                self.result = constants.ERROR
                self.logger.error("No profile with name '%s' exists." % name)
            else:
                self.logger.debug("Run finished with %s.", self.result)
            return self.result
        finally:
            self.logger.debug("Cleaning up transaction.")
            self.transaction.cleanup()
        
    def _run_profile(self, profile):
        process = profile.get_process(self.hook)
        if not process:
            self.logger.debug(
                "%s process skipped." % self.hook.capitalize()
            )
            return
        
        self.logger.debug("Running profile '%s'...", profile.name)
        protocol = Protocol(profile.name)
        # run the configured checks
        for name, config, interp in process.checks:
            self.logger.debug("Loading check %s...", name)
            check = self.checks.fetch(name, self.transaction)
            self.logger.debug("Starting check %s...", name)
            entry = check.run(config, interp)
            self.logger.debug(
                "Check %s finished with %s.", name, entry.result
            )
            protocol.append(entry)
            
            # run the configured handlers when a message was returned 
            if entry.msg:
                self.logger.debug(
                    "Running handler after check %s...", entry.check
                )
                self.handlers.singularize(self.transaction, process, entry)
                self.logger.debug(
                    "Handler after check %s finished.", entry.check
                )
            
            # cancel the _process chain when an abortonerror was detected.
            if interp == constants.ABORTONERROR and not protocol.success:
                msg = "Profile %s aborted after check %s."
                self.logger.debug(msg, profile.name, entry.check)
                break
        
        # cumulativ execution of all handlers.
        self.logger.debug("Running handler summarize...")
        self.handlers.summarize(self.transaction, process, protocol)
        self.logger.debug("Handler summarize finished.")
        
        if not protocol.success:
            self.result = constants.ERROR
        self.logger.debug("Profile %s finished.", profile.name)
示例#5
0
 def setup_class(cls):
     cls._cache = CheckManager()
     cls._buildin_check_names = [
         "PyLint", "Mantis", "AccessRights", "ASCIIEncoded", "CaseInsensitiveFilenameClash", 
         "Checkout", "Checkstyle", "Keywords", "Log", "RejectTabs", "UnitTests", "XMLValidator"]
     cls._init_pkg_resources_mocks(cls._buildin_check_names)
示例#6
0
class ConfigValidator(Validator):
    """
    The _config validator class validates a given ConfigObj object.
    """
    def __init__(self, propagate=1, override=None, excepts=False):
        """
        Constructor.
        
        :param propagate: If this evaluates to false, logging messages are not 
                          passed by this logger or by child loggers to higher 
                          level (ancestor) loggers.
        :type propagate: boolean
        
        :param override: Overrides the default log level for the intern logger.
        :type override: NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL
        """

        Validator.__init__(self)

        self.check_regex = re.compile(constants.CHECK_REGEX)
        self.handler_regex = re.compile(constants.HANDLER_REGEX)

        self.default_profile = False
        self.main = None
        self.errors = 0
        self.excepts = excepts

        self.valid_checks = []
        self.valid_handlers = []

        self.logger = LoggerFactory().create(self.__module__, propagate,
                                             override)

        self.check_manager = CheckManager()
        self.handler_manager = HandlerManager()

    def validate(self, main):
        """
        Validates the given ConfigObj object.
        
        :param main: The configuration that has to be validated.
        :type main: ConfigObj
        
        :raise ValidateError: When a the given ConfigObj object is not in a 
                              valid form a ValidateError is raised.
                              
        **Usage**
        
        >>> main = ConfigObj()
        >>> validator = ConfigValidator()
        >>> try:
        >>>    validator.validate(main)
        >>> except ValidateError, exc:
        >>>    print exc
        """

        self.default_profile = False
        self.errors = 0
        self.main = main

        self.logger.info("Starting validation...")
        try:
            if 'extends' in self.main:
                self.check('string', self.main['extends'])

            self.logger.info("Validating profiles...")
            if 'profiles' in self.main:
                for profile, config in self.main['profiles'].iteritems():
                    self._validate_profile(profile, config)
            if not self.default_profile:
                self.exception("No default profile found.")

            self.logger.info("Validating check configurations...")
            if 'checks' in self.main:
                self._validate_checks(self.main['checks'])
            else:
                self.logger.info("No check configurations defined.")

            self.logger.info("Validating handler configurations...")
            if 'handlers' in self.main:
                self._validate_handlers(self.main['handlers'])
            else:
                self.logger.info("No handler configurations defined.")
        finally:
            self.logger.info("Validation finished with %s.", self.errors)
        return self.errors

    def _validate_checks(self, config):
        """
        Validates all checks.
        """

        for check, conf in config.iteritems():
            if not check in self.check_manager.available_modules:
                msg = "The check '%s' is not available. Check the spelling."
                self.exception(msg % check)
                continue
            for check_config in conf.values():
                self._validate_check_config(check, check_config)

    def _validate_handlers(self, config):
        """
        Validates all handlers.
        """

        for handler, conf in config.iteritems():
            if not handler in self.handler_manager.available_modules:
                msg = "The handler '%s' is not available. Check the spelling."
                self.exception(msg % handler)
                continue
            for handler_config in conf.values():
                self._validate_handler_config(handler, handler_config)

    def _validate_profile(self, profile, config):
        """
        Validates a given profile.
        
        @param profile: The profile that has to be validated.
        @type profile: list<string>
        
        @param _config: The main _config.
        @type _config: ConfigObj
        """

        if 'regex' not in config:
            if self.default_profile:
                msg = "Default profile already exists. " \
                    + "Only one default profile is allowed."
                self.exception(msg)
            else:
                self.default_profile = True
                self.logger.info("Default profile found.")
        else:
            self.check('string', config['regex'])

        for commit in constants.HOOKS:
            if commit in config:
                self._validate_profile_commit(profile, commit, config[commit])

    def _validate_profile_commit(self, profile, commit, config):
        """
        Validates a given precommit or postcommit section.
        
        @param profile: The profile that has to be checked.
        @type profile: string
        
        @param commit: The pre or postcommit section of the profile.
        @type commit: constants.PRECOMMIT, constants.POSTCOMMIT
        
        @param _config: The main ConfigObj object.
        @type _config: ConfigObj
        """

        for key in ('checks', 'success', 'error'):
            if key not in config:
                msg = "No %s found for profile '%s' in %s process"
                self.exception(msg % (key, profile, commit))

        if 'default' in config and not config['default'] in constants.INTERPS:
            msg = "Unknown default value '%s' in profile '%s'"
            self.exception(msg % (config['default'], profile))

        self._validate_process_check(config['checks'])
        self._validate_process_handler(config['success'])
        self._validate_process_handler(config['error'])

    def _validate_process_check(self, process):
        """
        Validates the checks of the given process.
        
        @param process: The process that contains the checks.
        @type process: dict
        """

        process = self.check('string_list', process)
        for check in process:
            result = self.check_regex.search(check)
            name, config, interp = result.group("name", "config", "interp")
            if not name:
                self.logger.error("Empty checks are not allowed.")

            if config:
                try:
                    self.main['checks'][name][config]
                except KeyError:
                    msg = "Configuration '%s' for check '%s' is not defined"
                    self.exception(msg % (config, name))
            else:
                self._validate_emtpy_check_config(name)

            if interp and not interp in constants.INTERPS:
                msg = "Error interpretation '%s' is not valid."
                self.exception(msg % interp)

    def _validate_process_handler(self, process):
        """
        Validates the handlers of the given process.
        
        @param process: The process that contains the handlers.
        @type process: dict
        """

        process = self.check('string_list', process)
        for handler in process:
            result = self.handler_regex.search(handler)
            name, config = result.group("name", "config")

            if not name:
                self.logger.error("Empty handlers are not allowed.")

            if config:
                try:
                    self.main['handlers'][name][config]
                except KeyError:
                    msg = "Configuration '%s' for check '%s' is not defined"
                    self.exception(msg % (config, name))
            else:
                self._validate_empty_handler_config(name)

    def _validate_check_config(self, check, config):
        """
        Validates the _config that is specified by the given check.
        
        @param check: The check of which the _config has to be validated.
        @type check: string
        
        @param config: The _config of the check.
        @type config: Section
        """

        try:
            check_class = self.check_manager.load(check)
            check_class.__config__.from_config(config)
        except ImportError, exc:
            msg = "Unable to load check '%s'."
            self.exception(msg % check)
        except (ValueError, KeyError), exc:
            msg = "Validation error in check '%s': '%s'"
            self.exception(msg % (check, str(exc)))
示例#7
0
class RepoGuard(object):
    """
    Main RepoGuard class.
    """
    def __init__(self, hook, repository_path):
        """
        Constructor.
        
        :param hook: The hook that has to be executed. Valid values are 
                     constants.PRECOMMIT or constants.POSTCOMMIT.
        :type hook: constants.PRECOMMIT, constants.POSTCOMMIT.
        :param repository_path: The path to the current repository.
        :type repository_path: string
        """

        self.hook = hook
        self.repository_path = repository_path

        self.checks = CheckManager()
        self.handlers = HandlerManager()
        self.result = constants.SUCCESS
        self.main = None
        self.transaction = None

        self.logger = LoggerFactory().create(self.__module__)

    def load_transaction(self, name):
        """
        Load the transaction with the given name.
        
        :param name: The name of the current transaction.
        :type name: string
        """

        self.transaction = Transaction(self.repository_path, name)

    def load_config(self, tpl_dirs, config):
        """
        Load the project configuration.
        
        :param tpl_dirs: Path lists where all templates are located.
        :type tpl_dirs: string
                            
        :param config: The path or a splittedline project configuration string.
        :type config: string
        """

        self.logger.debug("Loading project configuration...")
        hooks_path = os.path.join(self.repository_path, "hooks")
        self.main = ProjectConfig(config, hooks_path, tpl_dirs)
        self.logger.debug("Project configuration loaded.")

    def validate(self):
        """
        Runs the internal validation process of the current loaded 
        configuration.
        
        :return: Returns the status code of the validator. succes = 0, error > 0
        :rtype: integer
        """

        validator = ConfigValidator(excepts=True)
        return validator.validate(self.main)

    def _combined_profile_regexes(self):
        """
        Returns a regular expression string which matches all 
        files that are covered by any special profile. A special
        profile defines a non-empty regex parameter.
        """

        combined_profile_regexes = ""
        for profile in self.main.profiles:
            if not profile.regex is None:
                combined_profile_regexes += "(%s)|" % profile.regex
        if not combined_profile_regexes:
            combined_profile_regexes = None
        else:
            combined_profile_regexes = combined_profile_regexes[:-1]
        return combined_profile_regexes

    def run(self):
        """
        Execution of the checking _process and handler handling.
        It is recommended to call the load_config method before 
        calling this method.
        
        :return: Returns the _process result as a constant string.
        :rtype: constants.SUCCESS, constants.ERROR
        """

        try:
            self.logger.debug("Running run...")
            combined_profile_regexes = self._combined_profile_regexes()
            self.logger.debug("Default ignore regex: %s",
                              combined_profile_regexes)

            # Process executing
            for profile in self.main.profiles:
                ignores = list()
                if not profile.regex is None:
                    self.transaction.profile = profile.regex
                else:
                    # default profile: covers all files
                    # which are not handled by a special profile
                    self.transaction.profile = ".*"
                    if not combined_profile_regexes is None:
                        ignores = [combined_profile_regexes]

                # if there are no files in this profile continue.
                if not self.transaction.get_files(ignore_list=ignores):
                    self.logger.debug("Profile '%s' skipped.", profile.name)
                    continue
                self._run_profile(profile)

            self.logger.debug("Run finished with %s.", self.result)
            return self.result
        finally:
            self.logger.debug("Cleaning up transaction.")
            self.transaction.cleanup()

    def run_profile(self, name):
        """ Runs a specific profile. """

        try:
            profile_found = False
            for profile in self.main.profiles:
                if name == profile.name:
                    self._run_profile(profile)
                    profile_found = True

            if not profile_found:
                self.result = constants.ERROR
                self.logger.error("No profile with name '%s' exists." % name)
            else:
                self.logger.debug("Run finished with %s.", self.result)
            return self.result
        finally:
            self.logger.debug("Cleaning up transaction.")
            self.transaction.cleanup()

    def _run_profile(self, profile):
        process = profile.get_process(self.hook)
        if not process:
            self.logger.debug("%s process skipped." % self.hook.capitalize())
            return

        self.logger.debug("Running profile '%s'...", profile.name)
        protocol = Protocol(profile.name)
        # run the configured checks
        for name, config, interp in process.checks:
            self.logger.debug("Loading check %s...", name)
            check = self.checks.fetch(name, self.transaction)
            self.logger.debug("Starting check %s...", name)
            entry = check.run(config, interp)
            self.logger.debug("Check %s finished with %s.", name, entry.result)
            protocol.append(entry)

            # run the configured handlers when a message was returned
            if entry.msg:
                self.logger.debug("Running handler after check %s...",
                                  entry.check)
                self.handlers.singularize(self.transaction, process, entry)
                self.logger.debug("Handler after check %s finished.",
                                  entry.check)

            # cancel the _process chain when an abortonerror was detected.
            if interp == constants.ABORTONERROR and not protocol.success:
                msg = "Profile %s aborted after check %s."
                self.logger.debug(msg, profile.name, entry.check)
                break

        # cumulativ execution of all handlers.
        self.logger.debug("Running handler summarize...")
        self.handlers.summarize(self.transaction, process, protocol)
        self.logger.debug("Handler summarize finished.")

        if not protocol.success:
            self.result = constants.ERROR
        self.logger.debug("Profile %s finished.", profile.name)