summaryrefslogtreecommitdiffstats
path: root/Tools/c-analyzer/cpython/_files.py
blob: ee9e46f7e5e95f5510772e10e9a49d3d12c65668 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import os.path

from c_common.fsutil import expand_filenames, iter_files_by_suffix
from . import REPO_ROOT, INCLUDE_DIRS, SOURCE_DIRS


GLOBS = [
    'Include/*.h',
    # Technically, this is covered by "Include/*.h":
    #'Include/cpython/*.h',
    'Include/internal/*.h',
    'Modules/**/*.h',
    'Modules/**/*.c',
    'Objects/**/*.h',
    'Objects/**/*.c',
    'Parser/**/*.h',
    'Parser/**/*.c',
    'Python/**/*.h',
    'Python/**/*.c',
]
LEVEL_GLOBS = {
    'stable': 'Include/*.h',
    'cpython': 'Include/cpython/*.h',
    'internal': 'Include/internal/*.h',
}


def resolve_filename(filename):
    orig = filename
    filename = os.path.normcase(os.path.normpath(filename))
    if os.path.isabs(filename):
        if os.path.relpath(filename, REPO_ROOT).startswith('.'):
            raise Exception(f'{orig!r} is outside the repo ({REPO_ROOT})')
        return filename
    else:
        return os.path.join(REPO_ROOT, filename)


def iter_filenames(*, search=False):
    if search:
        yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
        yield from iter_files_by_suffix(SOURCE_DIRS, ('.c',))
    else:
        globs = (os.path.join(REPO_ROOT, file) for file in GLOBS)
        yield from expand_filenames(globs)


def iter_header_files(filenames=None, *, levels=None):
    if not filenames:
        if levels:
            levels = set(levels)
            if 'private' in levels:
                levels.add('stable')
                levels.add('cpython')
            for level, glob in LEVEL_GLOBS.items():
                if level in levels:
                    yield from expand_filenames([glob])
        else:
            yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
        return

    for filename in filenames:
        orig = filename
        filename = resolve_filename(filename)
        if filename.endswith(os.path.sep):
            yield from iter_files_by_suffix(INCLUDE_DIRS, ('.h',))
        elif filename.endswith('.h'):
            yield filename
        else:
            # XXX Log it and continue instead?
            raise ValueError(f'expected .h file, got {orig!r}')