List known packages, available to the system.

    refresh
        force a refresh if set to True.
        If set to False (default) it depends on zypper if a refresh is
        executed.

    match (str)
        One of `exact`, `words`, `substrings`. Search for an `exact` match
        or for the whole `words` only. Default to `substrings` to patch
        partial words.

    provides (bool)
        Search for packages which provide the search strings.

    recommends (bool)
        Search for packages which recommend the search strings.

    requires (bool)
        Search for packages which require the search strings.

    suggests (bool)
        Search for packages which suggest the search strings.

    conflicts (bool)
        Search packages conflicting with search strings.

    obsoletes (bool)
        Search for packages which obsolete the search strings.

    file_list (bool)
        Search for a match in the file list of packages.

    search_descriptions (bool)
        Search also in package summaries and descriptions.

    case_sensitive (bool)
        Perform case-sensitive search.

    installed_only (bool)
        Show only installed packages.

    not_installed_only (bool)
        Show only packages which are not installed.

    details (bool)
        Show version and repository

    root
        operate on a different root directory.

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.search <criteria>

def search(criteria, refresh=False, **kwargs):
    '''
    List known packages, available to the system.

    refresh
        force a refresh if set to True.
        If set to False (default) it depends on zypper if a refresh is
        executed.

    match (str)
        One of `exact`, `words`, `substrings`. Search for an `exact` match
        or for the whole `words` only. Default to `substrings` to patch
        partial words.

    provides (bool)
        Search for packages which provide the search strings.

    recommends (bool)
        Search for packages which recommend the search strings.

    requires (bool)
        Search for packages which require the search strings.

    suggests (bool)
        Search for packages which suggest the search strings.

    conflicts (bool)
        Search packages conflicting with search strings.

    obsoletes (bool)
        Search for packages which obsolete the search strings.

    file_list (bool)
        Search for a match in the file list of packages.

    search_descriptions (bool)
        Search also in package summaries and descriptions.

    case_sensitive (bool)
        Perform case-sensitive search.

    installed_only (bool)
        Show only installed packages.

    not_installed_only (bool)
        Show only packages which are not installed.

    details (bool)
        Show version and repository

    root
        operate on a different root directory.

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.search <criteria>
    '''
    ALLOWED_SEARCH_OPTIONS = {
            'provides': '--provides',
            'recommends': '--recommends',
            'requires': '--requires',
            'suggests': '--suggests',
            'conflicts': '--conflicts',
            'obsoletes': '--obsoletes',
            'file_list': '--file-list',
            'search_descriptions': '--search-descriptions',
            'case_sensitive': '--case-sensitive',
            'installed_only': '--installed-only',
            'not_installed_only': '-u',
            'details': '--details'
            }

    root = kwargs.get('root', None)

    if refresh:
        refresh_db(root)

    cmd = ['search']
    if kwargs.get('match') == 'exact':
        cmd.append('--match-exact')
    elif kwargs.get('match') == 'words':
        cmd.append('--match-words')
    elif kwargs.get('match') == 'substrings':
        cmd.append('--match-substrings')

    for opt in kwargs:
        if opt in ALLOWED_SEARCH_OPTIONS:
            cmd.append(ALLOWED_SEARCH_OPTIONS.get(opt))

    cmd.append(criteria)
    solvables = __zypper__(root=root).nolock.noraise.xml.call(*cmd).getElementsByTagName('solvable')
    if not solvables:
        raise CommandExecutionError(
            'No packages found matching \'{0}\''.format(criteria)
        )

    out = {}
    for solvable in solvables:
        out[solvable.getAttribute('name')] = dict()
        for k, v in solvable.attributes.items():
            out[solvable.getAttribute('name')][k] = v

    return out