r'''
    .. versionadded:: 2015.8.0

    Ensure that the named config key is not present

    name
        The name of the configuration key to unset. This value can be a regex,
        but the regex must match the entire key name. For example, ``foo\.``
        would not match all keys in the ``foo`` section, it would be necessary
        to use ``foo\..+`` to do so.

    value_regex
        Regex indicating the values to unset for the matching key(s)

        .. note::
            This option behaves differently depending on whether or not ``all``
            is set to ``True``. If it is, then all values matching the regex
            will be deleted (this is the only way to delete multiple values
            from a multivar). If ``all`` is set to ``False``, then this state
            will fail if the regex matches more than one value in a multivar.

    all : False
        If ``True``, unset all matches

    repo
        Location of the git repository for which the config value should be
        set. Required unless ``global`` is set to ``True``.

    user
        User under which to run git commands. By default, commands are run by
        the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    global : False
        If ``True``, this will set a global git config option

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1


    **Examples:**

    .. code-block:: yaml

        # Value matching 'baz'
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - value_regex: 'baz'
            - repo: /path/to/repo

        # Ensure entire multivar is unset
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - all: True

        # Ensure all variables in 'foo' section are unset, including multivars
        mylocalrepo:
          git.config_unset:
            - name: 'foo\..+'
            - all: True

        # Ensure that global config value is unset
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - global: True

def config_unset(name,
                 value_regex=None,
                 repo=None,
                 user=None,
                 password=None,
                 output_encoding=None,
                 **kwargs):
    r'''
    .. versionadded:: 2015.8.0

    Ensure that the named config key is not present

    name
        The name of the configuration key to unset. This value can be a regex,
        but the regex must match the entire key name. For example, ``foo\.``
        would not match all keys in the ``foo`` section, it would be necessary
        to use ``foo\..+`` to do so.

    value_regex
        Regex indicating the values to unset for the matching key(s)

        .. note::
            This option behaves differently depending on whether or not ``all``
            is set to ``True``. If it is, then all values matching the regex
            will be deleted (this is the only way to delete multiple values
            from a multivar). If ``all`` is set to ``False``, then this state
            will fail if the regex matches more than one value in a multivar.

    all : False
        If ``True``, unset all matches

    repo
        Location of the git repository for which the config value should be
        set. Required unless ``global`` is set to ``True``.

    user
        User under which to run git commands. By default, commands are run by
        the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    global : False
        If ``True``, this will set a global git config option

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1


    **Examples:**

    .. code-block:: yaml

        # Value matching 'baz'
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - value_regex: 'baz'
            - repo: /path/to/repo

        # Ensure entire multivar is unset
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - all: True

        # Ensure all variables in 'foo' section are unset, including multivars
        mylocalrepo:
          git.config_unset:
            - name: 'foo\..+'
            - all: True

        # Ensure that global config value is unset
        mylocalrepo:
          git.config_unset:
            - name: foo.bar
            - global: True
    '''
    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': 'No matching keys are set'}

    # Sanitize kwargs and make sure that no invalid ones were passed. This
    # allows us to accept 'global' as an argument to this function without
    # shadowing global(), while also not allowing unwanted arguments to be
    # passed.
    kwargs = salt.utils.args.clean_kwargs(**kwargs)
    global_ = kwargs.pop('global', False)
    all_ = kwargs.pop('all', False)
    if kwargs:
        return _fail(
            ret,
            salt.utils.args.invalid_kwargs(kwargs, raise_exc=False)
        )

    if not global_ and not repo:
        return _fail(
            ret,
            'Non-global config options require the \'repo\' argument to be '
            'set'
        )

    if not isinstance(name, six.string_types):
        name = six.text_type(name)
    if value_regex is not None:
        if not isinstance(value_regex, six.string_types):
            value_regex = six.text_type(value_regex)

    # Ensure that the key regex matches the full key name
    key = '^' + name.lstrip('^').rstrip('$') + '$'

    # Get matching keys/values
    pre_matches = __salt__['git.config_get_regexp'](
        cwd=repo,
        key=key,
        value_regex=value_regex,
        user=user,
        password=password,
        ignore_retcode=True,
        output_encoding=output_encoding,
        **{'global': global_}
    )

    if not pre_matches:
        # No changes need to be made
        return ret

    # Perform sanity check on the matches. We can't proceed if the value_regex
    # matches more than one value in a given key, and 'all' is not set to True
    if not all_:
        greedy_matches = ['{0} ({1})'.format(x, ', '.join(y))
                          for x, y in six.iteritems(pre_matches)
                          if len(y) > 1]
        if greedy_matches:
            if value_regex is not None:
                return _fail(
                    ret,
                    'Multiple values are matched by value_regex for the '
                    'following keys (set \'all\' to True to force removal): '
                    '{0}'.format('; '.join(greedy_matches))
                )
            else:
                return _fail(
                    ret,
                    'Multivar(s) matched by the key expression (set \'all\' '
                    'to True to force removal): {0}'.format(
                        '; '.join(greedy_matches)
                    )
                )

    if __opts__['test']:
        ret['changes'] = pre_matches
        return _neutral_test(
            ret,
            '{0} key(s) would have value(s) unset'.format(len(pre_matches))
        )

    if value_regex is None:
        pre = pre_matches
    else:
        # Get all keys matching the key expression, so we can accurately report
        # on changes made.
        pre = __salt__['git.config_get_regexp'](
            cwd=repo,
            key=key,
            value_regex=None,
            user=user,
            password=password,
            ignore_retcode=True,
            output_encoding=output_encoding,
            **{'global': global_}
        )

    failed = []
    # Unset the specified value(s). There is no unset for regexes so loop
    # through the pre_matches dict and unset each matching key individually.
    for key_name in pre_matches:
        try:
            __salt__['git.config_unset'](
                cwd=repo,
                key=name,
                value_regex=value_regex,
                all=all_,
                user=user,
                password=password,
                output_encoding=output_encoding,
                **{'global': global_}
            )
        except CommandExecutionError as exc:
            msg = 'Failed to unset \'{0}\''.format(key_name)
            if value_regex is not None:
                msg += ' using value_regex \'{1}\''
            msg += ': ' + _strip_exc(exc)
            log.error(msg)
            failed.append(key_name)

    if failed:
        return _fail(
            ret,
            'Error(s) occurred unsetting values for the following keys (see '
            'the minion log for details): {0}'.format(', '.join(failed))
        )

    post = __salt__['git.config_get_regexp'](
        cwd=repo,
        key=key,
        value_regex=None,
        user=user,
        password=password,
        ignore_retcode=True,
        output_encoding=output_encoding,
        **{'global': global_}
    )

    for key_name in pre:
        if key_name not in post:
            ret['changes'][key_name] = pre[key_name]
        unset = [x for x in pre[key_name] if x not in post[key_name]]
        if unset:
            ret['changes'][key_name] = unset

    if value_regex is None:
        post_matches = post
    else:
        post_matches = __salt__['git.config_get_regexp'](
            cwd=repo,
            key=key,
            value_regex=value_regex,
            user=user,
            password=password,
            ignore_retcode=True,
            output_encoding=output_encoding,
            **{'global': global_}
        )

    if post_matches:
        failed = ['{0} ({1})'.format(x, ', '.join(y))
                  for x, y in six.iteritems(post_matches)]
        return _fail(
            ret,
            'Failed to unset value(s): {0}'.format('; '.join(failed))
        )

    ret['comment'] = 'Value(s) successfully unset'
    return ret