List the packages currently installed as a dict. By default, the dict
    contains versions as a comma separated string::

        {'<package_name>': '<version>[,<version>...]'}

    versions_as_list:
        If set to true, the versions are provided as a list

        {'<package_name>': ['<version>', '<version>']}

    root:
        operate on a different root directory.

    includes:
        List of types of packages to include (package, patch, pattern, product)
        By default packages are always included

    attr:
        If a list of package attributes is specified, returned value will
        contain them in addition to version, eg.::

        {'<package_name>': [{'version' : 'version', 'arch' : 'arch'}]}

        Valid attributes are: ``epoch``, ``version``, ``release``, ``arch``,
        ``install_date``, ``install_date_time_t``.

        If ``all`` is specified, all valid attributes will be returned.

            .. versionadded:: 2018.3.0

    removed:
        not supported

    purge_desired:
        not supported

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.list_pkgs
        salt '*' pkg.list_pkgs attr=version,arch
        salt '*' pkg.list_pkgs attr='["version", "arch"]'

def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs):
    '''
    List the packages currently installed as a dict. By default, the dict
    contains versions as a comma separated string::

        {'<package_name>': '<version>[,<version>...]'}

    versions_as_list:
        If set to true, the versions are provided as a list

        {'<package_name>': ['<version>', '<version>']}

    root:
        operate on a different root directory.

    includes:
        List of types of packages to include (package, patch, pattern, product)
        By default packages are always included

    attr:
        If a list of package attributes is specified, returned value will
        contain them in addition to version, eg.::

        {'<package_name>': [{'version' : 'version', 'arch' : 'arch'}]}

        Valid attributes are: ``epoch``, ``version``, ``release``, ``arch``,
        ``install_date``, ``install_date_time_t``.

        If ``all`` is specified, all valid attributes will be returned.

            .. versionadded:: 2018.3.0

    removed:
        not supported

    purge_desired:
        not supported

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.list_pkgs
        salt '*' pkg.list_pkgs attr=version,arch
        salt '*' pkg.list_pkgs attr='["version", "arch"]'
    '''
    versions_as_list = salt.utils.data.is_true(versions_as_list)
    # not yet implemented or not applicable
    if any([salt.utils.data.is_true(kwargs.get(x))
            for x in ('removed', 'purge_desired')]):
        return {}

    attr = kwargs.get('attr')
    if attr is not None:
        attr = salt.utils.args.split_input(attr)

    includes = includes if includes else []

    contextkey = 'pkg.list_pkgs'

    # TODO(aplanas): this cached value depends on the parameters
    if contextkey not in __context__:
        ret = {}
        cmd = ['rpm']
        if root:
            cmd.extend(['--root', root])
        cmd.extend(['-qa', '--queryformat',
                    salt.utils.pkg.rpm.QUERYFORMAT.replace('%{REPOID}', '(none)') + '\n'])
        output = __salt__['cmd.run'](cmd,
                                     python_shell=False,
                                     output_loglevel='trace')
        for line in output.splitlines():
            pkginfo = salt.utils.pkg.rpm.parse_pkginfo(
                line,
                osarch=__grains__['osarch']
            )
            if pkginfo:
                # see rpm version string rules available at https://goo.gl/UGKPNd
                pkgver = pkginfo.version
                epoch = ''
                release = ''
                if ':' in pkgver:
                    epoch, pkgver = pkgver.split(":", 1)
                if '-' in pkgver:
                    pkgver, release = pkgver.split("-", 1)
                all_attr = {
                    'epoch': epoch,
                    'version': pkgver,
                    'release': release,
                    'arch': pkginfo.arch,
                    'install_date': pkginfo.install_date,
                    'install_date_time_t': pkginfo.install_date_time_t
                }
                __salt__['pkg_resource.add_pkg'](ret, pkginfo.name, all_attr)

        _ret = {}
        for pkgname in ret:
            # Filter out GPG public keys packages
            if pkgname.startswith('gpg-pubkey'):
                continue
            _ret[pkgname] = sorted(ret[pkgname], key=lambda d: d['version'])

        for include in includes:
            if include in ('pattern', 'patch'):
                if include == 'pattern':
                    pkgs = list_installed_patterns(root=root)
                elif include == 'patch':
                    pkgs = list_installed_patches(root=root)
                else:
                    pkgs = []
                for pkg in pkgs:
                    pkg_extended_name = '{}:{}'.format(include, pkg)
                    info = info_available(pkg_extended_name,
                                          refresh=False,
                                          root=root)
                    _ret[pkg_extended_name] = [{
                        'epoch': None,
                        'version': info[pkg]['version'],
                        'release': None,
                        'arch': info[pkg]['arch'],
                        'install_date': None,
                        'install_date_time_t': None,
                    }]

        __context__[contextkey] = _ret

    return __salt__['pkg_resource.format_pkg_list'](
        __context__[contextkey],
        versions_as_list,
        attr)