Remove unwanted files based on specific criteria. Multiple criteria
    are OR’d together, so a file that is too large but is not old enough
    will still get tidied.

    If neither age nor size is given all files which match a pattern in
    matches will be removed.

    name
        The directory tree that should be tidied

    age
        Maximum age in days after which files are considered for removal

    matches
        List of regular expressions to restrict what gets removed.  Default: ['.*']

    rmdirs
        Whether or not it's allowed to remove directories

    size
        Maximum allowed file size. Files greater or equal to this size are
        removed. Doesn't apply to directories or symbolic links

    .. code-block:: yaml

        cleanup:
          file.tidied:
            - name: /tmp/salt_test
            - rmdirs: True
            - matches:
              - foo
              - b.*r

def tidied(name,
           age=0,
           matches=None,
           rmdirs=False,
           size=0,
           **kwargs):
    '''
    Remove unwanted files based on specific criteria. Multiple criteria
    are OR’d together, so a file that is too large but is not old enough
    will still get tidied.

    If neither age nor size is given all files which match a pattern in
    matches will be removed.

    name
        The directory tree that should be tidied

    age
        Maximum age in days after which files are considered for removal

    matches
        List of regular expressions to restrict what gets removed.  Default: ['.*']

    rmdirs
        Whether or not it's allowed to remove directories

    size
        Maximum allowed file size. Files greater or equal to this size are
        removed. Doesn't apply to directories or symbolic links

    .. code-block:: yaml

        cleanup:
          file.tidied:
            - name: /tmp/salt_test
            - rmdirs: True
            - matches:
              - foo
              - b.*r
    '''
    name = os.path.expanduser(name)

    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': ''}

    # Check preconditions
    if not os.path.isabs(name):
        return _error(ret, 'Specified file {0} is not an absolute path'.format(name))
    if not os.path.isdir(name):
        return _error(ret, '{0} does not exist or is not a directory.'.format(name))

    # Define some variables
    todelete = []
    today = date.today()

    # Compile regular expressions
    if matches is None:
        matches = ['.*']
    progs = []
    for regex in matches:
        progs.append(re.compile(regex))

    # Helper to match a given name against one or more pre-compiled regular
    # expressions
    def _matches(name):
        for prog in progs:
            if prog.match(name):
                return True
        return False

    # Iterate over given directory tree, depth-first
    for root, dirs, files in os.walk(top=name, topdown=False):
        # Check criteria for the found files and directories
        for elem in files + dirs:
            myage = 0
            mysize = 0
            deleteme = True
            path = os.path.join(root, elem)
            if os.path.islink(path):
                # Get age of symlink (not symlinked file)
                myage = abs(today - date.fromtimestamp(os.lstat(path).st_atime))
            elif elem in dirs:
                # Get age of directory, check if directories should be deleted at all
                myage = abs(today - date.fromtimestamp(os.path.getatime(path)))
                deleteme = rmdirs
            else:
                # Get age and size of regular file
                myage = abs(today - date.fromtimestamp(os.path.getatime(path)))
                mysize = os.path.getsize(path)
            # Verify against given criteria, collect all elements that should be removed
            if (mysize >= size or myage.days >= age) and _matches(name=elem) and deleteme:
                todelete.append(path)

    # Now delete the stuff
    if todelete:
        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = '{0} is set for tidy'.format(name)
            ret['changes'] = {'removed': todelete}
            return ret
        ret['changes']['removed'] = []
        # Iterate over collected items
        try:
            for path in todelete:
                __salt__['file.remove'](path, force=True)
                # Remember what we've removed, will appear in the summary
                ret['changes']['removed'].append(path)
        except CommandExecutionError as exc:
            return _error(ret, '{0}'.format(exc))
        # Set comment for the summary
        ret['comment'] = 'Removed {0} files or directories from directory {1}'.format(len(todelete), name)
    else:
        # Set comment in case there was nothing to remove
        ret['comment'] = 'Nothing to remove from directory {0}'.format(name)
    return ret