List the subvolumes present in the filesystem.

    path
        Mount point for the subvolume

    parent_id
        Print parent ID

    absolute
        Print all the subvolumes in the filesystem and distinguish
        between absolute and relative path with respect to the given
        <path>

    ogeneration
        Print the ogeneration of the subvolume

    generation
        Print the generation of the subvolume

    subvolumes
        Print only subvolumes below specified <path>

    uuid
        Print the UUID of the subvolume

    parent_uuid
        Print the parent uuid of subvolumes (and snapshots)

    sent_subvolume_uuid
        Print the UUID of the sent subvolume, where the subvolume is
        the result of a receive operation

    snapshots
        Only snapshot subvolumes in the filesystem will be listed

    readonly
        Only readonly subvolumes in the filesystem will be listed

    deleted
        Only deleted subvolumens that are ye not cleaned

    generation_cmp
        List subvolumes in the filesystem that its generation is >=,
        <= or = value. '+' means >= value, '-' means <= value, If
        there is neither '+' nor '-', it means = value

    ogeneration_cmp
        List subvolumes in the filesystem that its ogeneration is >=,
        <= or = value

    sort
        List subvolumes in order by specified items. Possible values:
        * rootid
        * gen
        * ogen
        * path
        You can add '+' or '-' in front of each items, '+' means
        ascending, '-' means descending. The default is ascending. You
        can combite it in a list.

    CLI Example:

    .. code-block:: bash

        salt '*' btrfs.subvolume_list /var/volumes/tmp
        salt '*' btrfs.subvolume_list /var/volumes/tmp path=True
        salt '*' btrfs.subvolume_list /var/volumes/tmp sort='[-rootid]'

def subvolume_list(path, parent_id=False, absolute=False,
                   ogeneration=False, generation=False,
                   subvolumes=False, uuid=False, parent_uuid=False,
                   sent_subvolume_uuid=False, snapshots=False,
                   readonly=False, deleted=False, generation_cmp=None,
                   ogeneration_cmp=None, sort=None):
    '''
    List the subvolumes present in the filesystem.

    path
        Mount point for the subvolume

    parent_id
        Print parent ID

    absolute
        Print all the subvolumes in the filesystem and distinguish
        between absolute and relative path with respect to the given
        <path>

    ogeneration
        Print the ogeneration of the subvolume

    generation
        Print the generation of the subvolume

    subvolumes
        Print only subvolumes below specified <path>

    uuid
        Print the UUID of the subvolume

    parent_uuid
        Print the parent uuid of subvolumes (and snapshots)

    sent_subvolume_uuid
        Print the UUID of the sent subvolume, where the subvolume is
        the result of a receive operation

    snapshots
        Only snapshot subvolumes in the filesystem will be listed

    readonly
        Only readonly subvolumes in the filesystem will be listed

    deleted
        Only deleted subvolumens that are ye not cleaned

    generation_cmp
        List subvolumes in the filesystem that its generation is >=,
        <= or = value. '+' means >= value, '-' means <= value, If
        there is neither '+' nor '-', it means = value

    ogeneration_cmp
        List subvolumes in the filesystem that its ogeneration is >=,
        <= or = value

    sort
        List subvolumes in order by specified items. Possible values:
        * rootid
        * gen
        * ogen
        * path
        You can add '+' or '-' in front of each items, '+' means
        ascending, '-' means descending. The default is ascending. You
        can combite it in a list.

    CLI Example:

    .. code-block:: bash

        salt '*' btrfs.subvolume_list /var/volumes/tmp
        salt '*' btrfs.subvolume_list /var/volumes/tmp path=True
        salt '*' btrfs.subvolume_list /var/volumes/tmp sort='[-rootid]'

    '''
    if sort and type(sort) is not list:
        raise CommandExecutionError('Sort parameter must be a list')

    valid_sorts = [
        ''.join((order, attrib)) for order, attrib in itertools.product(
            ('-', '', '+'), ('rootid', 'gen', 'ogen', 'path'))
    ]
    if sort and not all(s in valid_sorts for s in sort):
        raise CommandExecutionError('Value for sort not recognized')

    cmd = ['btrfs', 'subvolume', 'list']

    params = ((parent_id, '-p'),
              (absolute, '-a'),
              (ogeneration, '-c'),
              (generation, '-g'),
              (subvolumes, '-o'),
              (uuid, '-u'),
              (parent_uuid, '-q'),
              (sent_subvolume_uuid, '-R'),
              (snapshots, '-s'),
              (readonly, '-r'),
              (deleted, '-d'))
    cmd.extend(p[1] for p in params if p[0])

    if generation_cmp:
        cmd.extend(['-G', generation_cmp])

    if ogeneration_cmp:
        cmd.extend(['-C', ogeneration_cmp])

    # We already validated the content of the list
    if sort:
        cmd.append('--sort={}'.format(','.join(sort)))

    cmd.append(path)

    res = __salt__['cmd.run_all'](cmd)
    salt.utils.fsutils._verify_run(res)

    # Parse the output. ID and gen are always at the begining, and
    # path is always at the end. There is only one column that
    # contains space (top level), and the path value can also have
    # spaces. The issue is that we do not know how many spaces do we
    # have in the path name, so any classic solution based on split
    # will fail.
    #
    # This list is in order.
    columns = ('ID', 'gen', 'cgen', 'parent', 'top level', 'otime',
               'parent_uuid', 'received_uuid', 'uuid', 'path')
    result = []
    for line in res['stdout'].splitlines():
        table = {}
        for key in columns:
            value, line = _pop(line, key, key == 'path')
            if value:
                table[key.lower()] = value
        # If line is not empty here, we are not able to parse it
        if not line:
            result.append(table)

    return result