def glob_files(root_dir, includes=None, excludes=None, gitignore=None):
<EOL>if not includes:<EOL><INDENT>includes = ['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>includes = list(includes)<EOL><DEDENT>if excludes:<EOL><INDENT>excludes = list(excludes)<EOL><DEDENT>if gitignore:<EOL><INDENT>spec = pathspec.PathSpec.from_lines('<STR_LIT>', gitignore)<EOL>log.debug('<STR_LIT>', gitignore)<EOL><DEDENT>while includes:<EOL><INDENT>pattern = includes.pop(<NUM_LIT:0>)<EOL>if pattern.endswith('<STR_LIT>'):<EOL><INDENT>pattern += '<STR_LIT>'<EOL><DEDENT>matches = list(Path(root_dir).glob(pattern))<EOL>for m in matches:<EOL><INDENT>if m.is_dir():<EOL><INDENT>continue<EOL><DEDENT>pp = PurePath(m)<EOL>if includes and any(map(lambda p: pp.match(p), includes)):<EOL><INDENT>continue<EOL><DEDENT>if excludes and any(map(lambda p: pp.match(p), excludes)):<EOL><INDENT>continue<EOL><DEDENT>if gitignore and spec.match_file(str(m)):<EOL><INDENT>log.debug('<STR_LIT>',<EOL>str(m.relative_to(root_dir)))<EOL>continue<EOL><DEDENT>yield (str(m), str(m.relative_to(root_dir)))<EOL><DEDENT><DEDENT>
Powerful and flexible utility to search and tag files using patterns.
    :param root_dir: directory where we start the search
    :param includes: list or iterator of include pattern tuples (pattern, tag)
    :param excludes: list or iterator of exclude patterns
    :param gitignore: list of ignore patterns (gitwildcard format)
    :return: iterator of (absolute_path, relative_path)