Completed
Push — master ( 719867...30d2f4 )
by Ionel Cristian
01:05
created

FileStorage.location()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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