.. versionadded:: 2017.7.0

    Ensure that the package is downloaded, and that it is the correct version
    (if specified).

    Currently supported for the following pkg providers:
    :mod:`yumpkg <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`

    :param str name:
        The name of the package to be downloaded. This parameter is ignored if
        either "pkgs" is used. Additionally, please note that this option can
        only be used to download packages from a software repository.

    :param str version:
        Download a specific version of a package.

        .. important::
            As of version 2015.8.7, for distros which use yum/dnf, packages
            which have a version with a nonzero epoch (that is, versions which
            start with a number followed by a colon must have the epoch included
            when specifying the version number. For example:

            .. code-block:: yaml

                vim-enhanced:
                  pkg.downloaded:
                    - version: 2:7.4.160-1.el7

            An **ignore_epoch** argument has been added to which causes the
            epoch to be disregarded when the state checks to see if the desired
            version was installed.

            You can install a specific version when using the ``pkgs`` argument by
            including the version after the package:

            .. code-block:: yaml

                common_packages:
                  pkg.downloaded:
                    - pkgs:
                      - unzip
                      - dos2unix
                      - salt-minion: 2015.8.5-1.el6

    :param bool resolve_capabilities:
        Turn on resolving capabilities. This allow one to name "provides" or alias names for packages.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: yaml

        zsh:
          pkg.downloaded:
            - version: 5.0.5-4.63
            - fromrepo: "myrepository"

def downloaded(name,
               version=None,
               pkgs=None,
               fromrepo=None,
               ignore_epoch=None,
               **kwargs):
    '''
    .. versionadded:: 2017.7.0

    Ensure that the package is downloaded, and that it is the correct version
    (if specified).

    Currently supported for the following pkg providers:
    :mod:`yumpkg <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`

    :param str name:
        The name of the package to be downloaded. This parameter is ignored if
        either "pkgs" is used. Additionally, please note that this option can
        only be used to download packages from a software repository.

    :param str version:
        Download a specific version of a package.

        .. important::
            As of version 2015.8.7, for distros which use yum/dnf, packages
            which have a version with a nonzero epoch (that is, versions which
            start with a number followed by a colon must have the epoch included
            when specifying the version number. For example:

            .. code-block:: yaml

                vim-enhanced:
                  pkg.downloaded:
                    - version: 2:7.4.160-1.el7

            An **ignore_epoch** argument has been added to which causes the
            epoch to be disregarded when the state checks to see if the desired
            version was installed.

            You can install a specific version when using the ``pkgs`` argument by
            including the version after the package:

            .. code-block:: yaml

                common_packages:
                  pkg.downloaded:
                    - pkgs:
                      - unzip
                      - dos2unix
                      - salt-minion: 2015.8.5-1.el6

    :param bool resolve_capabilities:
        Turn on resolving capabilities. This allow one to name "provides" or alias names for packages.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: yaml

        zsh:
          pkg.downloaded:
            - version: 5.0.5-4.63
            - fromrepo: "myrepository"
    '''
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    if 'pkg.list_downloaded' not in __salt__:
        ret['result'] = False
        ret['comment'] = 'The pkg.downloaded state is not available on ' \
                         'this platform'
        return ret

    if not pkgs and isinstance(pkgs, list):
        ret['result'] = True
        ret['comment'] = 'No packages to download provided'
        return ret

    # If just a name (and optionally a version) is passed, just pack them into
    # the pkgs argument.
    if name and not pkgs:
        if version:
            pkgs = [{name: version}]
            version = None
        else:
            pkgs = [name]

    # It doesn't make sense here to received 'downloadonly' as kwargs
    # as we're explicitly passing 'downloadonly=True' to execution module.
    if 'downloadonly' in kwargs:
        del kwargs['downloadonly']

    pkgs, _refresh = _resolve_capabilities(pkgs, **kwargs)

    # Only downloading not yet downloaded packages
    targets = _find_download_targets(name,
                                     version,
                                     pkgs,
                                     fromrepo=fromrepo,
                                     ignore_epoch=ignore_epoch,
                                     **kwargs)
    if isinstance(targets, dict) and 'result' in targets:
        return targets
    elif not isinstance(targets, dict):
        ret['result'] = False
        ret['comment'] = 'An error was encountered while checking targets: ' \
                         '{0}'.format(targets)
        return ret

    if __opts__['test']:
        summary = ', '.join(targets)
        ret['comment'] = 'The following packages would be ' \
                         'downloaded: {0}'.format(summary)
        return ret

    try:
        pkg_ret = __salt__['pkg.install'](name=name,
                                          pkgs=pkgs,
                                          version=version,
                                          downloadonly=True,
                                          fromrepo=fromrepo,
                                          ignore_epoch=ignore_epoch,
                                          **kwargs)
        ret['result'] = True
        ret['changes'].update(pkg_ret)
    except CommandExecutionError as exc:
        ret = {'name': name, 'result': False}
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = 'An error was encountered while downloading ' \
                             'package(s): {0}'.format(exc)
        return ret

    new_pkgs = __salt__['pkg.list_downloaded'](**kwargs)
    ok, failed = _verify_install(targets, new_pkgs, ignore_epoch=ignore_epoch)

    if failed:
        summary = ', '.join([_get_desired_pkg(x, targets)
                             for x in failed])
        ret['result'] = False
        ret['comment'] = 'The following packages failed to ' \
                         'download: {0}'.format(summary)

    if not ret['changes'] and not ret['comment']:
        ret['result'] = True
        ret['comment'] = 'Packages are already downloaded: ' \
                         '{0}'.format(', '.join(targets))

    return ret