files   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 52
dl 0
loc 84
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
B create_filesystem_graph_model() 0 48 7
A is_ignored() 0 2 1
A load_ignore_patterns() 0 10 5
1
import fnmatch
2
import operator
3
import pathlib
4
from collections.abc import Iterable
5
6
from magika import Magika
7
8
import graphinate
9
10
11
def load_ignore_patterns(ignore_files: Iterable[str]) -> set[str]:
12
    patterns = set()
13
    for ignore_file in ignore_files:
14
        if pathlib.Path(ignore_file).exists():
15
            with open(ignore_file) as file:
16
                patterns.update(line.strip() for line in file if line.strip() and not line.startswith('#'))
17
18
    expand_patterns = {f"**/*{p}" if p.startswith('/') else f"**/*/{p}" for p in patterns}
19
    patterns.update(expand_patterns)
20
    return patterns
21
22
23
def is_ignored(path: pathlib.Path, patterns: Iterable[str]) -> bool:
24
    return any(fnmatch.fnmatch(path.as_posix(), pattern) for pattern in patterns)
25
26
27
def create_filesystem_graph_model(
28
        input_folder: str = '.',
29
        ignore_files: Iterable[str] = ('.ignore', '.gitignore', '.dockerignore')
30
):
31
    """
32
    Create a graph model of the file system structure.
33
34
    Args:
35
        input_folder (str): The folder to start the traversal from. Defaults to the current folder.
36
        ignore_files (Iterable): A list of files containing ignore patterns.
37
                             Defaults to ['.ignore', '.gitignore', '.dockerignore'].
38
39
    Returns:
40
        GraphModel: A graph model representing the file system structure.
41
    """
42
    graph_model = graphinate.model(name="File System Graph")
43
    magika = Magika()
44
45
    root_folder = pathlib.Path(input_folder)
46
    ignore_patterns = load_ignore_patterns(ignore_files)
47
48
    def file_type(path: pathlib.Path) -> str:
49
        if path.is_file():
50
            return magika.identify_path(path).output.ct_label
51
        elif path.is_dir():
52
            return 'folder'
53
        else:
54
            return 'other'
55
56
    as_posix = operator.methodcaller('as_posix')
57
58
    @graph_model.node(file_type, key=as_posix, value=as_posix)
59
    def file_node():
60
        yield root_folder
61
        for path in root_folder.rglob('*'):
62
            if not is_ignored(path, ignore_patterns, ):
63
                yield path
64
65
    @graph_model.edge()
66
    def contains():
67
        for path in root_folder.rglob('*'):
68
            if not is_ignored(path, ignore_patterns):
69
                yield {
70
                    'source': path.parent.as_posix(),
71
                    'target': path.as_posix()
72
                }
73
74
    return graph_model
75
76
77
if __name__ == '__main__':
78
    input_folder = '..'  # Default to the current folder
79
    ignore_files = ['.ignore', '.gitignore']  # Example list of ignore files
80
    filesystem_model = create_filesystem_graph_model(input_folder, ignore_files)
81
82
    schema = graphinate.builders.GraphQLBuilder(filesystem_model).build()
83
    graphinate.graphql.server(schema)
84