1import os.path
2
3from c_common.fsutil import expand_filenames, iter_files_by_suffix
4from . import REPO_ROOT, INCLUDE_DIRS, SOURCE_DIRS
5
6
7GLOBS = [
8    'Include/*.h',
9    # Technically, this is covered by "Include/*.h":
10    #'Include/cpython/*.h',
11    'Include/internal/*.h',
12    'Modules/**/*.h',
13    'Modules/**/*.c',
14    'Objects/**/*.h',
15    'Objects/**/*.c',
16    'Parser/**/*.h',
17    'Parser/**/*.c',
18    'Python/**/*.h',
19    'Python/**/*.c',
20]
21LEVEL_GLOBS = {
22    'stable': 'Include/*.h',
23    'cpython': 'Include/cpython/*.h',
24    'internal': 'Include/internal/*.h',
25}
26
27
28def resolve_filename(filename):
29    orig = filename
30    filename = os.path.normcase(os.path.normpath(filename))
31    if os.path.isabs(filename):
32        if os.path.relpath(filename, REPO_ROOT).startswith('.'):
33            raise Exception(f'{orig!r} is outside the repo ({REPO_ROOT})')
34        return filename
35    else:
36        return os.path.join(REPO_ROOT, filename)
37
38
39def iter_filenames(*, search=False):
40    if search:
41        yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
42        yield from iter_files_by_suffix(SOURCE_DIRS, ('.c',))
43    else:
44        globs = (os.path.join(REPO_ROOT, file) for file in GLOBS)
45        yield from expand_filenames(globs)
46
47
48def iter_header_files(filenames=None, *, levels=None):
49    if not filenames:
50        if levels:
51            levels = set(levels)
52            if 'private' in levels:
53                levels.add('stable')
54                levels.add('cpython')
55            for level, glob in LEVEL_GLOBS.items():
56                if level in levels:
57                    yield from expand_filenames([glob])
58        else:
59            yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
60        return
61
62    for filename in filenames:
63        orig = filename
64        filename = resolve_filename(filename)
65        if filename.endswith(os.path.sep):
66            yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
67        elif filename.endswith('.h'):
68            yield filename
69        else:
70            # XXX Log it and continue instead?
71            raise ValueError(f'expected .h file, got {orig!r}')
72