Completed
Push — master ( cbeac8...3a231d )
by Ionel Cristian
32s
created

FileStorage.load()   D

Complexity

Conditions 8

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
c 0
b 0
f 0
dl 0
loc 23
rs 4.7619
1
import json
2
import os
3
from pathlib import Path
4
5
from ..stats import normalize_stats
6
from ..utils import commonpath
7
from ..utils import safe_dumps
8
from ..utils import short_filename
9
10
11
class FileStorage(object):
12
    def __init__(self, path, logger, default_machine_id=None):
13
        self.path = Path(path)
14
        self.default_machine_id = default_machine_id
15
        if not self.path.exists():
16
            self.path.mkdir(parents=True)
17
        self.path = self.path.resolve()
18
        self.logger = logger
19
        self._cache = {}
20
21
    def __str__(self):
22
        return str(self.path)
23
24
    @property
25
    def location(self):
26
        return str(self.path.relative_to(os.getcwd()))
27
28
    def get(self, name):
29
        path = self.path.joinpath(self.default_machine_id) if self.default_machine_id else self.path
30
        if not path.exists():
31
            path.mkdir(parents=True)
32
        return path.joinpath(name)
33
34
    @property
35
    def _next_num(self):
36
        files = self.query("[0-9][0-9][0-9][0-9]_*")
37
        files.sort(reverse=True)
38
        if not files:
39
            return "0001"
40
        for f in files:
41
            try:
42
                return "%04i" % (int(str(f.name).split('_')[0]) + 1)
43
            except ValueError:
44
                raise
45
46
    def save(self, output_json, save):
47
        output_file = self.get("%s_%s.json" % (self._next_num, save))
48
        assert not output_file.exists()
49
        with output_file.open('wb') as fh:
50
            fh.write(safe_dumps(output_json, ensure_ascii=True, indent=4).encode())
51
        self.logger.info("Saved benchmark data in: %s" % output_file)
52
53
    def query(self, *globs_or_files):
54
        files = []
55
        globs = []
56
        if not globs_or_files:
57
            globs_or_files = "*",
58
59
        for globish in globs_or_files:
60
            candidate = Path(globish)
61
            try:
62
                is_file = candidate.is_file()
63
            except OSError:
64
                is_file = False
65
            if is_file:
66
                files.append(candidate)
67
                continue
68
69
            parts = candidate.parts
70
            if len(parts) > 2:
71
                raise ValueError("{0!r} isn't an existing file or acceptable glob. "
72
                                 "Expected 'platform-glob/filename-glob' or 'filename-glob'.".format(globish))
73
            elif len(parts) == 2:
74
                platform_glob, filename_glob = parts
75
            else:
76
                platform_glob = self.default_machine_id or "*"
77
                filename_glob, = parts or ['']
78
79
            filename_glob = filename_glob.rstrip("*") + "*.json"
80
            globs.append((platform_glob, filename_glob))
81
82
        files.extend((
83
            file
84
            for platform_glob, filename_glob in globs
85
            for path in self.path.glob(platform_glob)
86
            for file in path.glob(filename_glob)
87
        ))
88
        files.extend((
89
            file
90
            for _, filename_glob in globs
91
            for file in self.path.glob(filename_glob)
92
        ))
93
        return sorted(files, key=lambda file: (file.name, file.parent))
94
95
    def load(self, *globs_or_files):
96
        if not globs_or_files:
97
            globs_or_files = '[0-9][0-9][0-9][0-9]_',
98
99
        for file in self.query(*globs_or_files):
100
            if file in self._cache:
101
                data = self._cache[file]
102
            else:
103
                with file.open("rU") as fh:
104
                    try:
105
                        data = json.load(fh)
106
                        for bench in data["benchmarks"]:
107
                            normalize_stats(bench["stats"])
108
                    except Exception as exc:
109
                        self.logger.warn("BENCHMARK-C5",
110
                                         "Failed to load {0}: {1}".format(file, exc), fslocation=self.location)
111
                        continue
112
                self._cache[file] = data
113
            try:
114
                relpath = file.relative_to(self.path)
115
            except ValueError:
116
                relpath = file
117
            yield relpath, data
118
119
    def load_benchmarks(self, *globs_or_files):
120
        sources = [
121
            (short_filename(path), path, data)
122
            for path, data in self.load(*globs_or_files)
123
        ]
124
        common = len(commonpath([src for src, _, _ in sources])) if sources else 0
125
        for source, path, data in sources:
126
            source = source[common:].lstrip(r'\/')
127
128
            for bench in data["benchmarks"]:
129
                bench.update(bench.pop("stats"))
130
                bench['path'] = str(path)
131
                bench['source'] = source
132
                yield bench
133