Beispiel #1
0
    def _load_theme_config(self, name):
        """ Recursively load theme and any parent themes. """

        theme_dir = utils.get_theme_dir(name)
        self.dirs.append(theme_dir)

        try:
            file_path = os.path.join(theme_dir, 'elstir_theme.yml')
            with open(file_path, 'rb') as f:
                theme_config = utils.yaml_load(f)
                if theme_config is None:
                    theme_config = {}
        except OSError as e:
            log.debug(e)
            raise ValidationError(
                "The theme '{}' does not appear to have a configuration file. "
                "Please upgrade to a current version of the theme.".format(
                    name))

        log.debug("Loaded theme configuration for '%s' from '%s': %s", name,
                  file_path, theme_config)

        parent_theme = theme_config.pop('extends', None)
        if parent_theme:
            themes = utils.get_theme_names()
            if parent_theme not in themes:
                raise ValidationError(
                    "The theme '{}' inherits from '{}', which does not appear to be installed. "
                    "The available installed themes are: {}".format(
                        name, parent_theme, ', '.join(themes)))
            self._load_theme_config(parent_theme)

        self.static_templates.update(theme_config.pop('static_templates', []))
        self._vars.update(theme_config)
Beispiel #2
0
    def run_validation(self, value):
        if not isinstance(value, (list, tuple)):
            raise ValidationError('Invalid Markdown Extensions configuration')
        extensions = []
        for item in value:
            if isinstance(item, dict):
                if len(item) > 1:
                    raise ValidationError(
                        'Invalid Markdown Extensions configuration')
                ext, cfg = item.popitem()
                extensions.append(ext)
                if cfg is None:
                    continue
                if not isinstance(cfg, dict):
                    raise ValidationError(
                        'Invalid config options for Markdown '
                        "Extension '{}'.".format(ext))
                self.configdata[ext] = cfg
            elif isinstance(item, str):
                extensions.append(item)
            else:
                raise ValidationError(
                    'Invalid Markdown Extensions configuration')

        extensions = utils.reduce_list(self.builtins + extensions)

        # Confirm that Markdown considers extensions to be valid
        try:
            markdown.Markdown(extensions=extensions,
                              extension_configs=self.configdata)
        except Exception as e:
            raise ValidationError(e.args[0])

        return extensions
Beispiel #3
0
    def run_validation(self, value):
        if value is None:
            if self.required:
                raise ValidationError("Required configuration not provided.")
            else:
                return ()

        if not isinstance(value, Sequence):
            raise ValidationError('Expected a sequence of mappings, but a %s '
                                  'was given.' % type(value))

        return [self.item_config.validate(item) for item in value]
Beispiel #4
0
    def run_validation(self, value):

        if not isinstance(value, list):
            raise ValidationError("Expected a list, got {}".format(
                type(value)))

        if len(value) == 0:
            return

        config_types = {type(item) for item in value}
        if config_types.issubset({str, dict}):
            return value

        raise ValidationError("Invalid pages config. {} {}".format(
            config_types, {str, dict}))
Beispiel #5
0
    def run_validation(self, value):
        if value == '':
            return value

        try:
            parsed_url = urlparse(value)
        except (AttributeError, TypeError):
            raise ValidationError("Unable to parse the URL.")

        if parsed_url.scheme:
            if self.is_dir and not parsed_url.path.endswith('/'):
                parsed_url = parsed_url._replace(path=f'{parsed_url.path}/')
            return urlunparse(parsed_url)

        raise ValidationError(
            "The URL isn't valid, it should include the http:// (scheme)")
Beispiel #6
0
    def run_validation(self, value):
        if value not in self.choices:
            msg = ("Expected one of: {} but received: {}".format(
                self.choices, value))
        else:
            return value

        raise ValidationError(msg)
Beispiel #7
0
    def post_validation(self, config, key_name):
        if config.config_file_path is None:
            return

        # Validate that the dir is not the parent dir of the config file.
        if os.path.dirname(config.config_file_path) == config[key_name]:
            raise ValidationError(
                ("The '{0}' should not be the parent directory of the config "
                 "file. Use a child directory instead so that the '{0}' "
                 "is a sibling of the config file.").format(key_name))
Beispiel #8
0
 def run_validation(self, value):
     value = super().run_validation(value)
     if self.config_dir and not os.path.isabs(value):
         value = os.path.join(self.config_dir, value)
     if self.exists and not self.existence_test(value):
         raise ValidationError(
             "The path {path} isn't an existing {name}.".format(
                 path=value, name=self.name))
     value = os.path.abspath(value)
     assert isinstance(value, str)
     return value
Beispiel #9
0
    def load_plugin(self, name, config):
        if name not in self.installed_plugins:
            raise ValidationError(
                'The "{}" plugin is not installed'.format(name))

        Plugin = self.installed_plugins[name].load()

        if not issubclass(Plugin, plugins.BasePlugin):
            raise ValidationError('{}.{} must be a subclass of {}.{}'.format(
                Plugin.__module__, Plugin.__name__,
                plugins.BasePlugin.__module__, plugins.BasePlugin.__name__))

        plugin = Plugin()
        errors, warnings = plugin.load_config(config, self.config_file_path)
        self.warnings.extend(warnings)
        errors_message = '\n'.join(
            "Plugin '{}' value: '{}'. Error: {}".format(name, x, y)
            for x, y in errors)
        if errors_message:
            raise ValidationError(errors_message)
        return plugin
Beispiel #10
0
    def post_validation(self, config, key_name):
        theme_config = config[key_name]

        if not theme_config['name'] and 'custom_dir' not in theme_config:
            raise ValidationError(
                "At least one of 'theme.name' or 'theme.custom_dir' must be defined."
            )

        # Ensure custom_dir is an absolute path
        if 'custom_dir' in theme_config and not os.path.isabs(
                theme_config['custom_dir']):
            config_dir = os.path.dirname(config.config_file_path)
            theme_config['custom_dir'] = os.path.join(
                config_dir, theme_config['custom_dir'])

        if 'custom_dir' in theme_config and not os.path.isdir(
                theme_config['custom_dir']):
            raise ValidationError(
                "The path set in {name}.custom_dir ('{path}') does not exist.".
                format(path=theme_config['custom_dir'], name=key_name))

        config[key_name] = theme.Theme(**theme_config)
Beispiel #11
0
    def run_validation(self, value):

        if not isinstance(value, self._type):
            msg = ("Expected type: {} but received: {}".format(
                self._type, type(value)))
        elif self.length is not None and len(value) != self.length:
            msg = ("Expected type: {0} with length {2} but received: {1} with "
                   "length {3}").format(self._type, value, self.length,
                                        len(value))
        else:
            return value

        raise ValidationError(msg)
Beispiel #12
0
    def post_validation(self, config, key_name):

        super().post_validation(config, key_name)

        # Validate that the docs_dir and site_dir don't contain the
        # other as this will lead to copying back and forth on each
        # and eventually make a deep nested mess.
        if (config['docs_dir'] +
                os.sep).startswith(config['site_dir'].rstrip(os.sep) + os.sep):
            raise ValidationError(
                ("The 'docs_dir' should not be within the 'site_dir' as this "
                 "can mean the source files are overwritten by the output or "
                 "it will be deleted if --clean is passed to elstir build."
                 "(site_dir: '{}', docs_dir: '{}')").format(
                     config['site_dir'], config['docs_dir']))
        elif (config['site_dir'] +
              os.sep).startswith(config['docs_dir'].rstrip(os.sep) + os.sep):
            raise ValidationError(
                ("The 'site_dir' should not be within the 'docs_dir' as this "
                 "leads to the build directory being copied into itself and "
                 "duplicate nested files in the 'site_dir'."
                 "(site_dir: '{}', docs_dir: '{}')").format(
                     config['site_dir'], config['docs_dir']))
Beispiel #13
0
    def run_validation(self, value):
        try:
            host, port = value.rsplit(':', 1)
        except Exception:
            raise ValidationError("Must be a string of format 'IP:PORT'")

        if host != 'localhost':
            try:
                # Validate and normalize IP Address
                host = str(ipaddress.ip_address(host))
            except ValueError as e:
                raise ValidationError(e)

        try:
            port = int(port)
        except Exception:
            raise ValidationError("'{}' is not a valid port".format(port))

        class Address(namedtuple('Address', 'host port')):
            def __str__(self):
                return '{}:{}'.format(self.host, self.port)

        return Address(host, port)
Beispiel #14
0
    def validate(self, value):
        if value is None and self.default is not None:
            value = {'name': self.default}

        if isinstance(value, str):
            value = {'name': value}

        themes = utils.get_theme_names()

        if isinstance(value, dict):
            if 'name' in value:
                if value['name'] is None or value['name'] in themes:
                    return value

                raise ValidationError(
                    "Unrecognised theme name: '{}'. The available installed themes "
                    "are: {}".format(value['name'], ', '.join(themes)))

            raise ValidationError("No theme name set.")

        raise ValidationError(
            'Invalid type "{}". Expected a string or key/value pairs.'.format(
                type(value)))
Beispiel #15
0
    def run_validation(self, value):
        if not isinstance(value, (list, tuple)):
            raise ValidationError(
                'Invalid Plugins configuration. Expected a list of plugins')
        plgins = plugins.PluginCollection()
        for item in value:
            if isinstance(item, dict):
                if len(item) > 1:
                    raise ValidationError('Invalid Plugins configuration')
                name, cfg = item.popitem()
                cfg = cfg or {}  # Users may define a null (None) config
                if not isinstance(cfg, dict):
                    raise ValidationError('Invalid config options for '
                                          'the "{}" plugin.'.format(name))
                item = name
            else:
                cfg = {}

            if not isinstance(item, str):
                raise ValidationError('Invalid Plugins configuration')

            plgins[item] = self.load_plugin(item, cfg)

        return plgins
Beispiel #16
0
    def validate(self, value):
        """
        Perform some initial validation.

        If the option is empty (None) and isn't required, leave it as such. If
        it is empty but has a default, use that. Finally, call the
        run_validation method on the subclass unless.
        """

        if value is None:
            if self.default is not None:
                if hasattr(self.default, 'copy'):
                    # ensure no mutable values are assigned
                    value = self.default.copy()
                else:
                    value = self.default
            elif not self.required:
                return
            elif self.required:
                raise ValidationError("Required configuration not provided.")

        return self.run_validation(value)
Beispiel #17
0
 def run_validation(self, value):
     raise ValidationError('For internal use only.')