<gh_stars>10-100
# -*- coding: utf-8 -*-
"""
:copyright: Copyright 2020-2022 Sphinx Confluence Builder Contributors (AUTHORS)
:license: BSD-2-Clause (LICENSE)
"""

from sphinxcontrib.confluencebuilder.config.notifications import deprecated
from sphinxcontrib.confluencebuilder.config.notifications import warnings
from sphinxcontrib.confluencebuilder.config.validation import ConfigurationValidation
from sphinxcontrib.confluencebuilder.exceptions import ConfluenceConfigurationError
from requests.auth import AuthBase
import os

try:
    basestring  # pylint: disable=E0601
except NameError:
    basestring = str


def validate_configuration(builder):
    """
    validate a builder's configuration state

    This call will check if the provided builder's configuration has any issues
    with the existing configuration. For errors in the existing configuration,
    an `ConfluenceConfigurationError` exception will be thrown.

    In addition to errors, this call will also generate warning messages on
    other configuration issues such as deprecated configurations.

    Args:
        builder: the builder state to validate a configuration on
    """

    config = builder.config
    env = builder.app.env
    validator = ConfigurationValidation(builder)

    # ##################################################################

    # confluence_add_secnumbers
    validator.conf('confluence_add_secnumbers') \
             .bool()

    # ##################################################################

    # confluence_additional_mime_types
    validator.conf('confluence_additional_mime_types') \
             .strings(no_space=True)

    # ##################################################################

    # confluence_adv_aggressive_search
    validator.conf('confluence_adv_aggressive_search') \
             .bool()

    # ##################################################################

    # confluence_adv_hierarchy_child_macro
    validator.conf('confluence_adv_hierarchy_child_macro') \
             .bool()

    # ##################################################################

    # confluence_adv_permit_raw_html
    validator.conf('confluence_adv_permit_raw_html') \
             .bool()

    # ##################################################################

    # confluence_adv_trace_data
    validator.conf('confluence_adv_trace_data') \
             .bool()

    # ##################################################################

    # confluence_adv_writer_no_section_cap
    validator.conf('confluence_adv_writer_no_section_cap') \
             .bool()

    # ##################################################################

    # confluence_append_labels
    validator.conf('confluence_append_labels') \
             .bool()

    # ##################################################################

    # confluence_ask_password
    validator.conf('confluence_ask_password') \
             .bool()

    # ##################################################################

    # confluence_ask_user
    validator.conf('confluence_ask_user') \
             .bool()

    # ##################################################################

    # confluence_asset_force_standalone
    validator.conf('confluence_asset_force_standalone') \
             .bool()

    # ##################################################################

    # confluence_asset_override
    validator.conf('confluence_asset_override') \
             .bool()

    # ##################################################################

    validator.conf('confluence_ca_cert') \
             .file()

    # ##################################################################

    if config.confluence_client_cert is not None:
        client_cert = config.confluence_client_cert
        if isinstance(client_cert, tuple):
            cert_files = client_cert
        else:
            cert_files = (client_cert, None)

        if len(cert_files) != 2:
            raise ConfluenceConfigurationError('''\
confluence_client_cert is not a 2-tuple

The option 'confluence_client_cert' has been provided but there are too many
values. The client certificate can either be a file/path which defines a
certificate/key-pair, or a 2-tuple of the certificate and key.
''')

        for cert in cert_files:
            if cert and not os.path.isfile(os.path.join(env.srcdir, cert)):
                raise ConfluenceConfigurationError('''\
confluence_ca_cert missing certificate file

The option 'confluence_client_cert' has been provided to find a client
certificate file from a relative location, but the certificate could not be
found. Ensure the following file exists:

    {file}

'''.format(file=cert))

    # ##################################################################

    # confluence_client_cert_pass
    validator.conf('confluence_client_cert_pass') \
             .string()

    # ##################################################################

    # confluence_default_alignment
    try:
        validator.conf('confluence_default_alignment') \
                 .matching('left', 'center', 'right')
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_default_alignment' has been provided to override the
default alignment for tables, figures, etc. Accepted values include 'left',
'center' and 'right'.
'''.format(msg=e))

    # ##################################################################

    # confluence_disable_autogen_title
    validator.conf('confluence_disable_autogen_title') \
             .bool()

    # ##################################################################

    # confluence_disable_notifications
    validator.conf('confluence_disable_notifications') \
             .bool()

    # ##################################################################

    # confluence_disable_ssl_validation
    validator.conf('confluence_disable_ssl_validation') \
             .bool()

    # ##################################################################

    # confluence_domain_indices
    try:
        validator.conf('confluence_domain_indices').bool()
    except ConfluenceConfigurationError:
        try:
            validator.conf('confluence_domain_indices').strings()
        except ConfluenceConfigurationError:
            raise ConfluenceConfigurationError('''\
confluence_domain_indices is not a boolean or collection of strings

The option 'confluence_domain_indices' has been provided to indicate that
domain indices should be generated. This value can either be set to `True` or
set to a list of domains (strings) to be included.
''')

    # ##################################################################

    # confluence_file_suffix
    validator.conf('confluence_file_suffix') \
             .string()

    # ##################################################################

    # confluence_file_transform
    validator.conf('confluence_file_transform') \
             .callable_()

    # ##################################################################

    # confluence_footer_file
    try:
        validator.conf('confluence_footer_file') \
                 .string() \
                 .file()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_footer_file' has been provided to find a footer template
file from a path relative to the documentation source. Ensure the value is set
to a proper file path.
'''.format(msg=e))

    # ##################################################################

    # confluence_global_labels
    try:
        validator.conf('confluence_global_labels') \
                 .strings(no_space=True)
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_global_labels' can provide a collection to string values
to use as labels for published documentation. Each label value must be a string
that contains no spaces.
'''.format(msg=e))

    # ##################################################################

    # confluence_header_file
    try:
        validator.conf('confluence_header_file') \
                 .string() \
                 .file()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_header_file' has been provided to find a header template
file from a path relative to the documentation source. Ensure the value is set
to a proper file path.
'''.format(msg=e))

    # ##################################################################

    # confluence_ignore_titlefix_on_index
    validator.conf('confluence_ignore_titlefix_on_index') \
             .bool()

    # ##################################################################

    # confluence_include_search
    validator.conf('confluence_include_search') \
             .bool()

    # ##################################################################

    # confluence_jira_servers
    if config.confluence_jira_servers is not None:
        issue = False
        jira_servers = config.confluence_jira_servers

        if not isinstance(jira_servers, dict):
            issue = True
        else:
            for name, info in jira_servers.items():
                if not isinstance(name, basestring):
                    issue = True
                    break

                if not isinstance(info, dict):
                    issue = True
                    break

                jira_id = info.get('id')
                jira_name = info.get('name')

                if not (isinstance(jira_id, basestring) and
                        isinstance(jira_name, basestring)):
                    issue = True
                    break

        if issue:
            raise ConfluenceConfigurationError('''\
confluence_jira_servers is not properly formed

Jira server definitions should be a dictionary of string keys which contain
dictionaries with keys 'id' and 'name' which identify the Jira instances.
''')

    # ##################################################################

    # confluence_lang_transform
    validator.conf('confluence_lang_transform') \
             .callable_()

    # ##################################################################

    # confluence_latex_macro
    try:
        validator.conf('confluence_latex_macro').string()
    except ConfluenceConfigurationError:
        try:
            validator.conf('confluence_latex_macro').dict_str_str()

        except ConfluenceConfigurationError:
            raise ConfluenceConfigurationError('''\
confluence_latex_macro is not a string or dictionary of strings

The option 'confluence_latex_macro' has been provided to indicate that a
LaTeX content should be rendered with a LaTeX macro supported on a Confluence
instance. This value can either be set to a string of the macro to be used or
set to a dictionary of key-value strings for advanced options.
''')

        if config.confluence_latex_macro:
            conf_keys = config.confluence_latex_macro.keys()

            required_keys = [
                'block-macro',
                'inline-macro',
            ]

            if not all(name in conf_keys for name in required_keys):
                raise ConfluenceConfigurationError('''\
missing keys in confluence_latex_macro

The following keys are required:

 - {}
'''.format('\n - '.join(required_keys)))

    # ##################################################################

    # confluence_link_suffix
    validator.conf('confluence_link_suffix') \
             .string()

    # ##################################################################

    # confluence_link_transform
    validator.conf('confluence_link_transform') \
             .callable_()

    # ##################################################################

    # confluence_root_homepage
    validator.conf('confluence_root_homepage') \
             .bool()

    # ##################################################################

    # confluence_max_doc_depth
    try:
        validator.conf('confluence_max_doc_depth') \
                 .int_()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

When limiting the document depth permitted for a building/publishing event, the
defined maximum document depth must be defined as a non-negative integer value.

If planning to use a depth of zero, it is recommended to use the
'singleconfluence' builder instead.
'''.format(msg=e))

    # ##################################################################

    # confluence_navdocs_transform
    validator.conf('confluence_navdocs_transform') \
             .callable_()

    # ##################################################################

    validator.conf('confluence_parent_page') \
             .string()

    # ##################################################################

    validator.conf('confluence_parent_page_id_check') \
             .int_(positive=True)

    # ##################################################################

    # confluence_page_hierarchy
    validator.conf('confluence_page_hierarchy') \
             .bool()

    # ##################################################################

    # confluence_page_generation_notice
    validator.conf('confluence_page_generation_notice') \
             .bool()

    # ##################################################################

    # confluence_prev_next_buttons_location
    try:
        validator.conf('confluence_prev_next_buttons_location') \
                 .matching('bottom', 'both', 'top')
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_prev_next_buttons_location' has been configured to enable
navigational buttons onto generated pages. Accepted values include 'bottom',
'both' and 'top'.
'''.format(msg=e))

    # ##################################################################

    # confluence_proxy
    validator.conf('confluence_proxy') \
             .string()

    # ##################################################################

    # confluence_publish_allowlist
    # confluence_publish_denylist
    publish_list_options = [
        'confluence_publish_allowlist',
        'confluence_publish_denylist',
    ]

    for option in publish_list_options:
        value = getattr(config, option)
        if not value:
            continue

        # if provided via command line, treat as a list
        def conf_translate(value):
            if option in config['overrides'] and isinstance(value, basestring):
                value = value.split(',')
            return value
        value = conf_translate(value)

        try:
            validator.conf(option, conf_translate) \
                     .string_or_strings()

            if isinstance(value, basestring):
                validator.docnames_from_file()
            else:
                validator.docnames()
        except ConfluenceConfigurationError as e:
            raise ConfluenceConfigurationError('''\
{msg}

The value type permitted for this publish list option can either be a list of
document names or a string pointing to a file containing documents. Document
names are relative to the documentation's source directory.
'''.format(msg=e))

    # ##################################################################

    validator.conf('confluence_publish_delay') \
             .float_(positive=True)

    # ##################################################################

    # confluence_publish_dryrun
    validator.conf('confluence_publish_dryrun') \
             .bool()

    # ##################################################################

    # confluence_publish_headers
    validator.conf('confluence_publish_headers') \
             .dict_str_str()

    # ##################################################################

    # confluence_publish_onlynew
    validator.conf('confluence_publish_onlynew') \
             .bool()

    # ##################################################################

    # confluence_publish_postfix
    validator.conf('confluence_publish_postfix') \
             .string()

    # ##################################################################

    # confluence_publish_prefix
    validator.conf('confluence_publish_prefix') \
             .string()

    # ##################################################################

    validator.conf('confluence_publish_root') \
             .int_(positive=True)

    # ##################################################################

    # confluence_publish_token
    validator.conf('confluence_publish_token') \
             .string()

    # ##################################################################

    # confluence_purge
    validator.conf('confluence_purge') \
             .bool()

    # ##################################################################

    # confluence_purge_from_root
    validator.conf('confluence_purge_from_root') \
             .bool()

    # ##################################################################

    # confluence_remove_title
    validator.conf('confluence_remove_title') \
             .bool()

    # ##################################################################

    # confluence_request_session_override
    validator.conf('confluence_request_session_override') \
             .callable_()

    # ##################################################################

    # confluence_secnumber_suffix
    validator.conf('confluence_secnumber_suffix') \
             .string()

    # ##################################################################

    # confluence_server_auth
    if config.confluence_server_auth is not None:
        if not issubclass(type(config.confluence_server_auth), AuthBase):
            raise ConfluenceConfigurationError('''\
confluence_server_auth is not an implementation of requests.auth.AuthBase

Providing a custom authentication for Requests requires an implementation that
inherits 'requests.auth.AuthBase'. For more information, please consult the
following:

    requests -- Authentication
    https://requests.readthedocs.io/en/latest/user/authentication/
''')

    # ##################################################################

    # confluence_server_cookies
    validator.conf('confluence_server_cookies') \
             .dict_str_str()

    # ##################################################################

    # confluence_server_pass
    validator.conf('confluence_server_pass') \
             .string()

    # ##################################################################

    # confluence_server_url
    validator.conf('confluence_server_url') \
             .string()

    # ##################################################################

    # confluence_server_user
    validator.conf('confluence_server_user') \
             .string()

    # ##################################################################

    # confluence_sourcelink
    validator.conf('confluence_sourcelink') \
             .dict_str_str()

    if config.confluence_sourcelink:
        sourcelink = config.confluence_sourcelink

        # check if a supported template type is provided
        supported_types = [
            'bitbucket',
            'github',
            'gitlab',
        ]
        if 'type' in sourcelink:
            if sourcelink['type'] not in supported_types:
                raise ConfluenceConfigurationError('''\
unsupported type provided in confluence_sourcelink

The following types are supported:

 - {}
'''.format('\n - '.join(supported_types)))

            # ensure requires options are set
            required = [
                'owner',
                'repo',
                'version',
            ]
            if not all(k in sourcelink for k in required):
                raise ConfluenceConfigurationError('''\
required option missing in confluence_sourcelink

The following options are required for the provided template type:

 - {}
'''.format('\n - '.join(required)))

        # if not using a template type, ensure url is set
        elif 'url' not in sourcelink or not sourcelink['url']:
            raise ConfluenceConfigurationError('''\
url option is not set in confluence_sourcelink

If a template type is not being configured for a source link,
the `url` field must be configured.
''')

        reserved = [
            'page',
            'suffix',
        ]
        if any(k in sourcelink for k in reserved):
            raise ConfluenceConfigurationError('''\
reserved option set in confluence_sourcelink

The following options are reserved with confluence_sourcelink
and cannot be set:

 - {}
'''.format('\n - '.join(reserved)))

    # ##################################################################

    # confluence_space_key
    validator.conf('confluence_space_key') \
             .string()

    # ##################################################################

    # confluence_title_overrides
    validator.conf('confluence_title_overrides') \
             .dict_str_str()

    # ##################################################################

    # confluence_timeout
    try:
        validator.conf('confluence_timeout') \
                 .int_()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

A configured timeout should be set to a duration, in seconds, before any network
request to timeout after inactivity. This should be set to a positive integer
value (e.g. 2).
'''.format(msg=e))

    # ##################################################################

    # confluence_use_index
    validator.conf('confluence_use_index') \
             .bool()

    # ##################################################################

    # confluence_version_comment
    validator.conf('confluence_version_comment') \
             .string()

    # ##################################################################

    # confluence_watch
    validator.conf('confluence_watch') \
             .bool()

    # ##################################################################

    if config.confluence_publish:
        if not config.confluence_server_url:
            raise ConfluenceConfigurationError('''\
confluence server url not provided

While publishing has been configured using 'confluence_publish', the Confluence
server URL has not. Ensure 'confluence_server_url' has been set to target
Confluence instance to be published to.
''')

        if not config.confluence_space_key and not config.confluence_space_name:
            raise ConfluenceConfigurationError('''\
confluence space key not provided

While publishing has been configured using 'confluence_publish', the Confluence
space key has not. Ensure 'confluence_space_key' has been set to space's key
which content should be published under.
''')

        if (config.confluence_ask_password and not config.confluence_server_user
                and not config.confluence_ask_user):
            raise ConfluenceConfigurationError('''\
confluence username not provided

A publishing password has been flagged with 'confluence_ask_password';
however, no username has been configured. Ensure 'confluence_server_user' is
properly set with the publisher's Confluence username or have
'confluence_ask_user' set to provide a username.
''')

        if config.confluence_server_pass:
            if not config.confluence_server_user:
                raise ConfluenceConfigurationError('''\
confluence username not provided

A publishing password has been configured with 'confluence_server_pass';
however, no username has been configured. Ensure 'confluence_server_user' is
properly set with the publisher's Confluence username.
''')

        if config.confluence_parent_page_id_check:
            if not config.confluence_parent_page:
                raise ConfluenceConfigurationError('''\
parent page (holder) name not set

When a parent page identifier check has been configured with the option
'confluence_parent_page_id_check', no parent page name has been provided with
the 'confluence_parent_page' option. Ensure the name of the parent page name
is provided as well.
''')

        if config.confluence_publish_root:
            if config.confluence_parent_page:
                raise ConfluenceConfigurationError('''\
conflicting publish point configurations

When configuring for a publishing container, a user can configure for either
'confluence_parent_page' or 'confluence_publish_root'; however, both cannot be
configured at the same time.
''')

    # ##################################################################

    # singleconfluence_toctree
    validator.conf('singleconfluence_toctree') \
             .bool()

    # ##################################################################

    # inform users of additional configuration information
    deprecated(validator)
    warnings(validator)

# -*- coding: utf-8 -*-
"""
:copyright: Copyright 2020-2022 Sphinx Confluence Builder Contributors (AUTHORS)
:license: BSD-2-Clause (LICENSE)
"""

from sphinxcontrib.confluencebuilder.config.notifications import deprecated
from sphinxcontrib.confluencebuilder.config.notifications import warnings
from sphinxcontrib.confluencebuilder.config.validation import ConfigurationValidation
from sphinxcontrib.confluencebuilder.exceptions import ConfluenceConfigurationError
from requests.auth import AuthBase
import os

try:
    basestring  # pylint: disable=E0601
except NameError:
    basestring = str


def validate_configuration(builder):
    """
    validate a builder's configuration state

    This call will check if the provided builder's configuration has any issues
    with the existing configuration. For errors in the existing configuration,
    an `ConfluenceConfigurationError` exception will be thrown.

    In addition to errors, this call will also generate warning messages on
    other configuration issues such as deprecated configurations.

    Args:
        builder: the builder state to validate a configuration on
    """

    config = builder.config
    env = builder.app.env
    validator = ConfigurationValidation(builder)

    # ##################################################################

    # confluence_add_secnumbers
    validator.conf('confluence_add_secnumbers') \
             .bool()

    # ##################################################################

    # confluence_additional_mime_types
    validator.conf('confluence_additional_mime_types') \
             .strings(no_space=True)

    # ##################################################################

    # confluence_adv_aggressive_search
    validator.conf('confluence_adv_aggressive_search') \
             .bool()

    # ##################################################################

    # confluence_adv_hierarchy_child_macro
    validator.conf('confluence_adv_hierarchy_child_macro') \
             .bool()

    # ##################################################################

    # confluence_adv_permit_raw_html
    validator.conf('confluence_adv_permit_raw_html') \
             .bool()

    # ##################################################################

    # confluence_adv_trace_data
    validator.conf('confluence_adv_trace_data') \
             .bool()

    # ##################################################################

    # confluence_adv_writer_no_section_cap
    validator.conf('confluence_adv_writer_no_section_cap') \
             .bool()

    # ##################################################################

    # confluence_append_labels
    validator.conf('confluence_append_labels') \
             .bool()

    # ##################################################################

    # confluence_ask_password
    validator.conf('confluence_ask_password') \
             .bool()

    # ##################################################################

    # confluence_ask_user
    validator.conf('confluence_ask_user') \
             .bool()

    # ##################################################################

    # confluence_asset_force_standalone
    validator.conf('confluence_asset_force_standalone') \
             .bool()

    # ##################################################################

    # confluence_asset_override
    validator.conf('confluence_asset_override') \
             .bool()

    # ##################################################################

    validator.conf('confluence_ca_cert') \
             .file()

    # ##################################################################

    if config.confluence_client_cert is not None:
        client_cert = config.confluence_client_cert
        if isinstance(client_cert, tuple):
            cert_files = client_cert
        else:
            cert_files = (client_cert, None)

        if len(cert_files) != 2:
            raise ConfluenceConfigurationError('''\
confluence_client_cert is not a 2-tuple

The option 'confluence_client_cert' has been provided but there are too many
values. The client certificate can either be a file/path which defines a
certificate/key-pair, or a 2-tuple of the certificate and key.
''')

        for cert in cert_files:
            if cert and not os.path.isfile(os.path.join(env.srcdir, cert)):
                raise ConfluenceConfigurationError('''\
confluence_ca_cert missing certificate file

The option 'confluence_client_cert' has been provided to find a client
certificate file from a relative location, but the certificate could not be
found. Ensure the following file exists:

    {file}

'''.format(file=cert))

    # ##################################################################

    # confluence_client_cert_pass
    validator.conf('confluence_client_cert_pass') \
             .string()

    # ##################################################################

    # confluence_default_alignment
    try:
        validator.conf('confluence_default_alignment') \
                 .matching('left', 'center', 'right')
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_default_alignment' has been provided to override the
default alignment for tables, figures, etc. Accepted values include 'left',
'center' and 'right'.
'''.format(msg=e))

    # ##################################################################

    # confluence_disable_autogen_title
    validator.conf('confluence_disable_autogen_title') \
             .bool()

    # ##################################################################

    # confluence_disable_notifications
    validator.conf('confluence_disable_notifications') \
             .bool()

    # ##################################################################

    # confluence_disable_ssl_validation
    validator.conf('confluence_disable_ssl_validation') \
             .bool()

    # ##################################################################

    # confluence_domain_indices
    try:
        validator.conf('confluence_domain_indices').bool()
    except ConfluenceConfigurationError:
        try:
            validator.conf('confluence_domain_indices').strings()
        except ConfluenceConfigurationError:
            raise ConfluenceConfigurationError('''\
confluence_domain_indices is not a boolean or collection of strings

The option 'confluence_domain_indices' has been provided to indicate that
domain indices should be generated. This value can either be set to `True` or
set to a list of domains (strings) to be included.
''')

    # ##################################################################

    # confluence_file_suffix
    validator.conf('confluence_file_suffix') \
             .string()

    # ##################################################################

    # confluence_file_transform
    validator.conf('confluence_file_transform') \
             .callable_()

    # ##################################################################

    # confluence_footer_file
    try:
        validator.conf('confluence_footer_file') \
                 .string() \
                 .file()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_footer_file' has been provided to find a footer template
file from a path relative to the documentation source. Ensure the value is set
to a proper file path.
'''.format(msg=e))

    # ##################################################################

    # confluence_global_labels
    try:
        validator.conf('confluence_global_labels') \
                 .strings(no_space=True)
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_global_labels' can provide a collection to string values
to use as labels for published documentation. Each label value must be a string
that contains no spaces.
'''.format(msg=e))

    # ##################################################################

    # confluence_header_file
    try:
        validator.conf('confluence_header_file') \
                 .string() \
                 .file()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_header_file' has been provided to find a header template
file from a path relative to the documentation source. Ensure the value is set
to a proper file path.
'''.format(msg=e))

    # ##################################################################

    # confluence_ignore_titlefix_on_index
    validator.conf('confluence_ignore_titlefix_on_index') \
             .bool()

    # ##################################################################

    # confluence_include_search
    validator.conf('confluence_include_search') \
             .bool()

    # ##################################################################

    # confluence_jira_servers
    if config.confluence_jira_servers is not None:
        issue = False
        jira_servers = config.confluence_jira_servers

        if not isinstance(jira_servers, dict):
            issue = True
        else:
            for name, info in jira_servers.items():
                if not isinstance(name, basestring):
                    issue = True
                    break

                if not isinstance(info, dict):
                    issue = True
                    break

                jira_id = info.get('id')
                jira_name = info.get('name')

                if not (isinstance(jira_id, basestring) and
                        isinstance(jira_name, basestring)):
                    issue = True
                    break

        if issue:
            raise ConfluenceConfigurationError('''\
confluence_jira_servers is not properly formed

Jira server definitions should be a dictionary of string keys which contain
dictionaries with keys 'id' and 'name' which identify the Jira instances.
''')

    # ##################################################################

    # confluence_lang_transform
    validator.conf('confluence_lang_transform') \
             .callable_()

    # ##################################################################

    # confluence_latex_macro
    try:
        validator.conf('confluence_latex_macro').string()
    except ConfluenceConfigurationError:
        try:
            validator.conf('confluence_latex_macro').dict_str_str()

        except ConfluenceConfigurationError:
            raise ConfluenceConfigurationError('''\
confluence_latex_macro is not a string or dictionary of strings

The option 'confluence_latex_macro' has been provided to indicate that a
LaTeX content should be rendered with a LaTeX macro supported on a Confluence
instance. This value can either be set to a string of the macro to be used or
set to a dictionary of key-value strings for advanced options.
''')

        if config.confluence_latex_macro:
            conf_keys = config.confluence_latex_macro.keys()

            required_keys = [
                'block-macro',
                'inline-macro',
            ]

            if not all(name in conf_keys for name in required_keys):
                raise ConfluenceConfigurationError('''\
missing keys in confluence_latex_macro

The following keys are required:

 - {}
'''.format('\n - '.join(required_keys)))

    # ##################################################################

    # confluence_link_suffix
    validator.conf('confluence_link_suffix') \
             .string()

    # ##################################################################

    # confluence_link_transform
    validator.conf('confluence_link_transform') \
             .callable_()

    # ##################################################################

    # confluence_root_homepage
    validator.conf('confluence_root_homepage') \
             .bool()

    # ##################################################################

    # confluence_max_doc_depth
    try:
        validator.conf('confluence_max_doc_depth') \
                 .int_()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

When limiting the document depth permitted for a building/publishing event, the
defined maximum document depth must be defined as a non-negative integer value.

If planning to use a depth of zero, it is recommended to use the
'singleconfluence' builder instead.
'''.format(msg=e))

    # ##################################################################

    # confluence_navdocs_transform
    validator.conf('confluence_navdocs_transform') \
             .callable_()

    # ##################################################################

    validator.conf('confluence_parent_page') \
             .string()

    # ##################################################################

    validator.conf('confluence_parent_page_id_check') \
             .int_(positive=True)

    # ##################################################################

    # confluence_page_hierarchy
    validator.conf('confluence_page_hierarchy') \
             .bool()

    # ##################################################################

    # confluence_page_generation_notice
    validator.conf('confluence_page_generation_notice') \
             .bool()

    # ##################################################################

    # confluence_prev_next_buttons_location
    try:
        validator.conf('confluence_prev_next_buttons_location') \
                 .matching('bottom', 'both', 'top')
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

The option 'confluence_prev_next_buttons_location' has been configured to enable
navigational buttons onto generated pages. Accepted values include 'bottom',
'both' and 'top'.
'''.format(msg=e))

    # ##################################################################

    # confluence_proxy
    validator.conf('confluence_proxy') \
             .string()

    # ##################################################################

    # confluence_publish_allowlist
    # confluence_publish_denylist
    publish_list_options = [
        'confluence_publish_allowlist',
        'confluence_publish_denylist',
    ]

    for option in publish_list_options:
        value = getattr(config, option)
        if not value:
            continue

        # if provided via command line, treat as a list
        def conf_translate(value):
            if option in config['overrides'] and isinstance(value, basestring):
                value = value.split(',')
            return value
        value = conf_translate(value)

        try:
            validator.conf(option, conf_translate) \
                     .string_or_strings()

            if isinstance(value, basestring):
                validator.docnames_from_file()
            else:
                validator.docnames()
        except ConfluenceConfigurationError as e:
            raise ConfluenceConfigurationError('''\
{msg}

The value type permitted for this publish list option can either be a list of
document names or a string pointing to a file containing documents. Document
names are relative to the documentation's source directory.
'''.format(msg=e))

    # ##################################################################

    validator.conf('confluence_publish_delay') \
             .float_(positive=True)

    # ##################################################################

    # confluence_publish_dryrun
    validator.conf('confluence_publish_dryrun') \
             .bool()

    # ##################################################################

    # confluence_publish_headers
    validator.conf('confluence_publish_headers') \
             .dict_str_str()

    # ##################################################################

    # confluence_publish_onlynew
    validator.conf('confluence_publish_onlynew') \
             .bool()

    # ##################################################################

    # confluence_publish_postfix
    validator.conf('confluence_publish_postfix') \
             .string()

    # ##################################################################

    # confluence_publish_prefix
    validator.conf('confluence_publish_prefix') \
             .string()

    # ##################################################################

    validator.conf('confluence_publish_root') \
             .int_(positive=True)

    # ##################################################################

    # confluence_publish_token
    validator.conf('confluence_publish_token') \
             .string()

    # ##################################################################

    # confluence_purge
    validator.conf('confluence_purge') \
             .bool()

    # ##################################################################

    # confluence_purge_from_root
    validator.conf('confluence_purge_from_root') \
             .bool()

    # ##################################################################

    # confluence_remove_title
    validator.conf('confluence_remove_title') \
             .bool()

    # ##################################################################

    # confluence_request_session_override
    validator.conf('confluence_request_session_override') \
             .callable_()

    # ##################################################################

    # confluence_secnumber_suffix
    validator.conf('confluence_secnumber_suffix') \
             .string()

    # ##################################################################

    # confluence_server_auth
    if config.confluence_server_auth is not None:
        if not issubclass(type(config.confluence_server_auth), AuthBase):
            raise ConfluenceConfigurationError('''\
confluence_server_auth is not an implementation of requests.auth.AuthBase

Providing a custom authentication for Requests requires an implementation that
inherits 'requests.auth.AuthBase'. For more information, please consult the
following:

    requests -- Authentication
    https://requests.readthedocs.io/en/latest/user/authentication/
''')

    # ##################################################################

    # confluence_server_cookies
    validator.conf('confluence_server_cookies') \
             .dict_str_str()

    # ##################################################################

    # confluence_server_pass
    validator.conf('confluence_server_pass') \
             .string()

    # ##################################################################

    # confluence_server_url
    validator.conf('confluence_server_url') \
             .string()

    # ##################################################################

    # confluence_server_user
    validator.conf('confluence_server_user') \
             .string()

    # ##################################################################

    # confluence_sourcelink
    validator.conf('confluence_sourcelink') \
             .dict_str_str()

    if config.confluence_sourcelink:
        sourcelink = config.confluence_sourcelink

        # check if a supported template type is provided
        supported_types = [
            'bitbucket',
            'github',
            'gitlab',
        ]
        if 'type' in sourcelink:
            if sourcelink['type'] not in supported_types:
                raise ConfluenceConfigurationError('''\
unsupported type provided in confluence_sourcelink

The following types are supported:

 - {}
'''.format('\n - '.join(supported_types)))

            # ensure requires options are set
            required = [
                'owner',
                'repo',
                'version',
            ]
            if not all(k in sourcelink for k in required):
                raise ConfluenceConfigurationError('''\
required option missing in confluence_sourcelink

The following options are required for the provided template type:

 - {}
'''.format('\n - '.join(required)))

        # if not using a template type, ensure url is set
        elif 'url' not in sourcelink or not sourcelink['url']:
            raise ConfluenceConfigurationError('''\
url option is not set in confluence_sourcelink

If a template type is not being configured for a source link,
the `url` field must be configured.
''')

        reserved = [
            'page',
            'suffix',
        ]
        if any(k in sourcelink for k in reserved):
            raise ConfluenceConfigurationError('''\
reserved option set in confluence_sourcelink

The following options are reserved with confluence_sourcelink
and cannot be set:

 - {}
'''.format('\n - '.join(reserved)))

    # ##################################################################

    # confluence_space_key
    validator.conf('confluence_space_key') \
             .string()

    # ##################################################################

    # confluence_title_overrides
    validator.conf('confluence_title_overrides') \
             .dict_str_str()

    # ##################################################################

    # confluence_timeout
    try:
        validator.conf('confluence_timeout') \
                 .int_()
    except ConfluenceConfigurationError as e:
        raise ConfluenceConfigurationError('''\
{msg}

A configured timeout should be set to a duration, in seconds, before any network
request to timeout after inactivity. This should be set to a positive integer
value (e.g. 2).
'''.format(msg=e))

    # ##################################################################

    # confluence_use_index
    validator.conf('confluence_use_index') \
             .bool()

    # ##################################################################

    # confluence_version_comment
    validator.conf('confluence_version_comment') \
             .string()

    # ##################################################################

    # confluence_watch
    validator.conf('confluence_watch') \
             .bool()

    # ##################################################################

    if config.confluence_publish:
        if not config.confluence_server_url:
            raise ConfluenceConfigurationError('''\
confluence server url not provided

While publishing has been configured using 'confluence_publish', the Confluence
server URL has not. Ensure 'confluence_server_url' has been set to target
Confluence instance to be published to.
''')

        if not config.confluence_space_key and not config.confluence_space_name:
            raise ConfluenceConfigurationError('''\
confluence space key not provided

While publishing has been configured using 'confluence_publish', the Confluence
space key has not. Ensure 'confluence_space_key' has been set to space's key
which content should be published under.
''')

        if (config.confluence_ask_password and not config.confluence_server_user
                and not config.confluence_ask_user):
            raise ConfluenceConfigurationError('''\
confluence username not provided

A publishing password has been flagged with 'confluence_ask_password';
however, no username has been configured. Ensure 'confluence_server_user' is
properly set with the publisher's Confluence username or have
'confluence_ask_user' set to provide a username.
''')

        if config.confluence_server_pass:
            if not config.confluence_server_user:
                raise ConfluenceConfigurationError('''\
confluence username not provided

A publishing password has been configured with 'confluence_server_pass';
however, no username has been configured. Ensure 'confluence_server_user' is
properly set with the publisher's Confluence username.
''')

        if config.confluence_parent_page_id_check:
            if not config.confluence_parent_page:
                raise ConfluenceConfigurationError('''\
parent page (holder) name not set

When a parent page identifier check has been configured with the option
'confluence_parent_page_id_check', no parent page name has been provided with
the 'confluence_parent_page' option. Ensure the name of the parent page name
is provided as well.
''')

        if config.confluence_publish_root:
            if config.confluence_parent_page:
                raise ConfluenceConfigurationError('''\
conflicting publish point configurations

When configuring for a publishing container, a user can configure for either
'confluence_parent_page' or 'confluence_publish_root'; however, both cannot be
configured at the same time.
''')

    # ##################################################################

    # singleconfluence_toctree
    validator.conf('singleconfluence_toctree') \
             .bool()

    # ##################################################################

    # inform users of additional configuration information
    deprecated(validator)
    warnings(validator)
# -*- coding: utf-8 -*- :copyright: Copyright 2020-2022 Sphinx Confluence Builder Contributors (AUTHORS) :license: BSD-2-Clause (LICENSE) # pylint: disable=E0601 validate a builder's configuration state      This call will check if the provided builder's configuration has any issues     with the existing configuration. For errors in the existing configuration,     an `ConfluenceConfigurationError` exception will be thrown.      In addition to errors, this call will also generate warning messages on     other configuration issues such as deprecated configurations.      Args:         builder: the builder state to validate a configuration on # ################################################################## # confluence_add_secnumbers # ################################################################## # confluence_additional_mime_types # ################################################################## # confluence_adv_aggressive_search # ################################################################## # confluence_adv_hierarchy_child_macro # ################################################################## # confluence_adv_permit_raw_html # ################################################################## # confluence_adv_trace_data # ################################################################## # confluence_adv_writer_no_section_cap # ################################################################## # confluence_append_labels # ################################################################## # confluence_ask_password # ################################################################## # confluence_ask_user # ################################################################## # confluence_asset_force_standalone # ################################################################## # confluence_asset_override # ################################################################## # ################################################################## \ confluence_client_cert is not a 2-tuple  The option 'confluence_client_cert' has been provided but there are too many values. The client certificate can either be a file/path which defines a certificate/key-pair, or a 2-tuple of the certificate and key. \ confluence_ca_cert missing certificate file  The option 'confluence_client_cert' has been provided to find a client certificate file from a relative location, but the certificate could not be found. Ensure the following file exists:      {file} # ################################################################## # confluence_client_cert_pass # ################################################################## # confluence_default_alignment \ {msg}  The option 'confluence_default_alignment' has been provided to override the default alignment for tables, figures, etc. Accepted values include 'left', 'center' and 'right'. # ################################################################## # confluence_disable_autogen_title # ################################################################## # confluence_disable_notifications # ################################################################## # confluence_disable_ssl_validation # ################################################################## # confluence_domain_indices \ confluence_domain_indices is not a boolean or collection of strings  The option 'confluence_domain_indices' has been provided to indicate that domain indices should be generated. This value can either be set to `True` or set to a list of domains (strings) to be included. # ################################################################## # confluence_file_suffix # ################################################################## # confluence_file_transform # ################################################################## # confluence_footer_file \ {msg}  The option 'confluence_footer_file' has been provided to find a footer template file from a path relative to the documentation source. Ensure the value is set to a proper file path. # ################################################################## # confluence_global_labels \ {msg}  The option 'confluence_global_labels' can provide a collection to string values to use as labels for published documentation. Each label value must be a string that contains no spaces. # ################################################################## # confluence_header_file \ {msg}  The option 'confluence_header_file' has been provided to find a header template file from a path relative to the documentation source. Ensure the value is set to a proper file path. # ################################################################## # confluence_ignore_titlefix_on_index # ################################################################## # confluence_include_search # ################################################################## # confluence_jira_servers \ confluence_jira_servers is not properly formed  Jira server definitions should be a dictionary of string keys which contain dictionaries with keys 'id' and 'name' which identify the Jira instances. # ################################################################## # confluence_lang_transform # ################################################################## # confluence_latex_macro \ confluence_latex_macro is not a string or dictionary of strings  The option 'confluence_latex_macro' has been provided to indicate that a LaTeX content should be rendered with a LaTeX macro supported on a Confluence instance. This value can either be set to a string of the macro to be used or set to a dictionary of key-value strings for advanced options. \ missing keys in confluence_latex_macro  The following keys are required:   - {} # ################################################################## # confluence_link_suffix # ################################################################## # confluence_link_transform # ################################################################## # confluence_root_homepage # ################################################################## # confluence_max_doc_depth \ {msg}  When limiting the document depth permitted for a building/publishing event, the defined maximum document depth must be defined as a non-negative integer value.  If planning to use a depth of zero, it is recommended to use the 'singleconfluence' builder instead. # ################################################################## # confluence_navdocs_transform # ################################################################## # ################################################################## # ################################################################## # confluence_page_hierarchy # ################################################################## # confluence_page_generation_notice # ################################################################## # confluence_prev_next_buttons_location \ {msg}  The option 'confluence_prev_next_buttons_location' has been configured to enable navigational buttons onto generated pages. Accepted values include 'bottom', 'both' and 'top'. # ################################################################## # confluence_proxy # ################################################################## # confluence_publish_allowlist # confluence_publish_denylist # if provided via command line, treat as a list \ {msg}  The value type permitted for this publish list option can either be a list of document names or a string pointing to a file containing documents. Document names are relative to the documentation's source directory. # ################################################################## # ################################################################## # confluence_publish_dryrun # ################################################################## # confluence_publish_headers # ################################################################## # confluence_publish_onlynew # ################################################################## # confluence_publish_postfix # ################################################################## # confluence_publish_prefix # ################################################################## # ################################################################## # confluence_publish_token # ################################################################## # confluence_purge # ################################################################## # confluence_purge_from_root # ################################################################## # confluence_remove_title # ################################################################## # confluence_request_session_override # ################################################################## # confluence_secnumber_suffix # ################################################################## # confluence_server_auth \ confluence_server_auth is not an implementation of requests.auth.AuthBase  Providing a custom authentication for Requests requires an implementation that inherits 'requests.auth.AuthBase'. For more information, please consult the following:      requests -- Authentication     https://requests.readthedocs.io/en/latest/user/authentication/ # ################################################################## # confluence_server_cookies # ################################################################## # confluence_server_pass # ################################################################## # confluence_server_url # ################################################################## # confluence_server_user # ################################################################## # confluence_sourcelink # check if a supported template type is provided \ unsupported type provided in confluence_sourcelink  The following types are supported:   - {} # ensure requires options are set \ required option missing in confluence_sourcelink  The following options are required for the provided template type:   - {} # if not using a template type, ensure url is set \ url option is not set in confluence_sourcelink  If a template type is not being configured for a source link, the `url` field must be configured. \ reserved option set in confluence_sourcelink  The following options are reserved with confluence_sourcelink and cannot be set:   - {} # ################################################################## # confluence_space_key # ################################################################## # confluence_title_overrides # ################################################################## # confluence_timeout \ {msg}  A configured timeout should be set to a duration, in seconds, before any network request to timeout after inactivity. This should be set to a positive integer value (e.g. 2). # ################################################################## # confluence_use_index # ################################################################## # confluence_version_comment # ################################################################## # confluence_watch # ################################################################## \ confluence server url not provided  While publishing has been configured using 'confluence_publish', the Confluence server URL has not. Ensure 'confluence_server_url' has been set to target Confluence instance to be published to. \ confluence space key not provided  While publishing has been configured using 'confluence_publish', the Confluence space key has not. Ensure 'confluence_space_key' has been set to space's key which content should be published under. \ confluence username not provided  A publishing password has been flagged with 'confluence_ask_password'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username or have 'confluence_ask_user' set to provide a username. \ confluence username not provided  A publishing password has been configured with 'confluence_server_pass'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username. \ parent page (holder) name not set  When a parent page identifier check has been configured with the option 'confluence_parent_page_id_check', no parent page name has been provided with the 'confluence_parent_page' option. Ensure the name of the parent page name is provided as well. \ conflicting publish point configurations  When configuring for a publishing container, a user can configure for either 'confluence_parent_page' or 'confluence_publish_root'; however, both cannot be configured at the same time. # ################################################################## # singleconfluence_toctree # ################################################################## # inform users of additional configuration information