Generate the list of files managed by a recurse state

def _gen_recurse_managed_files(
        name,
        source,
        keep_symlinks=False,
        include_pat=None,
        exclude_pat=None,
        maxdepth=None,
        include_empty=False,
        **kwargs):
    '''
    Generate the list of files managed by a recurse state
    '''

    # Convert a relative path generated from salt master paths to an OS path
    # using "name" as the base directory
    def full_path(master_relpath):
        return os.path.join(name, _salt_to_os_path(master_relpath))

    # Process symlinks and return the updated filenames list
    def process_symlinks(filenames, symlinks):
        for lname, ltarget in six.iteritems(symlinks):
            srelpath = posixpath.relpath(lname, srcpath)
            if not _is_valid_relpath(srelpath, maxdepth=maxdepth):
                continue
            if not salt.utils.stringutils.check_include_exclude(
                    srelpath, include_pat, exclude_pat):
                continue
            # Check for all paths that begin with the symlink
            # and axe it leaving only the dirs/files below it.
            # This needs to use list() otherwise they reference
            # the same list.
            _filenames = list(filenames)
            for filename in _filenames:
                if filename.startswith(lname):
                    log.debug(
                        '** skipping file ** %s, it intersects a symlink',
                        filename
                    )
                    filenames.remove(filename)
            # Create the symlink along with the necessary dirs.
            # The dir perms/ownership will be adjusted later
            # if needed
            managed_symlinks.add((srelpath, ltarget))

            # Add the path to the keep set in case clean is set to True
            keep.add(full_path(srelpath))
        vdir.update(keep)
        return filenames

    managed_files = set()
    managed_directories = set()
    managed_symlinks = set()
    keep = set()
    vdir = set()

    srcpath, senv = salt.utils.url.parse(source)
    if senv is None:
        senv = __env__
    if not srcpath.endswith(posixpath.sep):
        # we're searching for things that start with this *directory*.
        srcpath = srcpath + posixpath.sep
    fns_ = __salt__['cp.list_master'](senv, srcpath)

    # If we are instructed to keep symlinks, then process them.
    if keep_symlinks:
        # Make this global so that emptydirs can use it if needed.
        symlinks = __salt__['cp.list_master_symlinks'](senv, srcpath)
        fns_ = process_symlinks(fns_, symlinks)

    for fn_ in fns_:
        if not fn_.strip():
            continue

        # fn_ here is the absolute (from file_roots) source path of
        # the file to copy from; it is either a normal file or an
        # empty dir(if include_empty==true).

        relname = salt.utils.data.decode(posixpath.relpath(fn_, srcpath))
        if not _is_valid_relpath(relname, maxdepth=maxdepth):
            continue

        # Check if it is to be excluded. Match only part of the path
        # relative to the target directory
        if not salt.utils.stringutils.check_include_exclude(
                relname, include_pat, exclude_pat):
            continue
        dest = full_path(relname)
        dirname = os.path.dirname(dest)
        keep.add(dest)

        if dirname not in vdir:
            # verify the directory perms if they are set
            managed_directories.add(dirname)
            vdir.add(dirname)

        src = salt.utils.url.create(fn_, saltenv=senv)
        managed_files.add((dest, src))

    if include_empty:
        mdirs = __salt__['cp.list_master_dirs'](senv, srcpath)
        for mdir in mdirs:
            relname = posixpath.relpath(mdir, srcpath)
            if not _is_valid_relpath(relname, maxdepth=maxdepth):
                continue
            if not salt.utils.stringutils.check_include_exclude(
                    relname, include_pat, exclude_pat):
                continue
            mdest = full_path(relname)
            # Check for symlinks that happen to point to an empty dir.
            if keep_symlinks:
                islink = False
                for link in symlinks:
                    if mdir.startswith(link, 0):
                        log.debug(
                            '** skipping empty dir ** %s, it intersects a '
                            'symlink', mdir
                        )
                        islink = True
                        break
                if islink:
                    continue

            managed_directories.add(mdest)
            keep.add(mdest)

    return managed_files, managed_directories, managed_symlinks, keep