Commit | Line | Data |
---|---|---|
efdd48db JR |
1 | # Copyright (c) 2017 Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com> |
2 | # | |
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
4 | # of this software and associated documentation files (the "Software"), to deal | |
5 | # in the Software without restriction, including without limitation the rights | |
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
7 | # copies of the Software, and to permit persons to whom the Software is | |
8 | # furnished to do so, subject to the following conditions: | |
9 | # | |
10 | # The above copyright notice and this permission notice shall be included in all | |
11 | # copies or substantial portions of the Software. | |
12 | # | |
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
19 | # SOFTWARE. | |
20 | ||
de9b991b JR |
21 | import os |
22 | import logging | |
23 | import yaml | |
fe7b987e | 24 | import pickle |
de9b991b JR |
25 | |
26 | import lttng_ivc.utils.project as Project | |
fe7b987e | 27 | import lttng_ivc.settings as Settings |
de9b991b | 28 | |
cb87ff89 | 29 | from lttng_ivc.utils.utils import sha256_checksum |
de9b991b JR |
30 | |
31 | _logger = logging.getLogger('project.factory') | |
de9b991b JR |
32 | _project_constructor = { |
33 | 'babeltrace': Project.Babeltrace, | |
34 | 'lttng-modules': Project.Lttng_modules, | |
35 | 'lttng-tools': Project.Lttng_tools, | |
36 | 'lttng-ust': Project.Lttng_ust, | |
37 | } | |
38 | ||
fe7b987e JR |
39 | __projects_cache = {} |
40 | ||
cb87ff89 JR |
41 | _project_py_checksum = sha256_checksum(Settings.project_py_file_location) |
42 | ||
de9b991b | 43 | _markers = None |
fe7b987e JR |
44 | with open(Settings.run_configuration_file, 'r') as stream: |
45 | # This is voluntary static across calls, no need to perform this | |
de9b991b JR |
46 | # every time. |
47 | _markers = yaml.load(stream) | |
48 | ||
49 | ||
fe7b987e | 50 | def get_fresh(label, tmpdir): |
de9b991b JR |
51 | if label not in _markers: |
52 | # TODO: specialized exception, handle it caller-side so the caller | |
53 | # can decide to skip or fail test. | |
54 | raise Exception('Label is no present') | |
55 | marker = _markers[label] | |
56 | constructor = _project_constructor[marker['project']] | |
57 | path = marker['path'] | |
58 | sha1 = marker['sha1'] | |
59 | return constructor(label, path, sha1, tmpdir) | |
fe7b987e JR |
60 | |
61 | ||
62 | def _validate_pickle(pickle, label): | |
97d494b0 | 63 | _logger.debug("Checking validate for {} {}".format(pickle, |
cb87ff89 JR |
64 | label)) |
65 | if pickle._py_file_checksum != _project_py_checksum: | |
66 | _logger.warn("Project py file changed".format(pickle.label, | |
67 | label)) | |
68 | return False | |
69 | ||
fe7b987e JR |
70 | if pickle.label != label: |
71 | _logger.warn("Label {} and {} are not the same".format(pickle.label, | |
cb87ff89 | 72 | label)) |
fe7b987e JR |
73 | return False |
74 | if pickle.sha1 != _markers[label]['sha1']: | |
75 | _logger.warn("Sha1 {} and {} are not the same".format(pickle.sha1, | |
76 | _markers[label]['sha1'])) | |
77 | return False | |
78 | ||
79 | deps = _markers[label]['deps'] | |
80 | if len(deps) != len(pickle.dependencies): | |
81 | _logger.warn("Len {} and {} are not the same".format(len(deps), | |
82 | len(pickle.dependencies))) | |
83 | return False | |
84 | for dep in deps: | |
85 | if dep not in pickle.dependencies: | |
86 | _logger.warn("Dep {} is not in {}".format(dep, | |
87 | pickle.dependencies)) | |
88 | return False | |
89 | else: | |
90 | _logger.debug("Calling validate {} {}".format(pickle.dependencies[dep], | |
91 | dep)) | |
92 | valid = _validate_pickle(pickle.dependencies[dep], dep) | |
93 | if not valid: | |
94 | return False | |
95 | return True | |
96 | ||
97 | ||
98 | def get_precook(label): | |
99 | """ | |
100 | Retrieve a precooked immutable projects from a cache if present | |
101 | otherwise the project is built, installed and cached for future access. | |
102 | """ | |
103 | if label not in _markers: | |
104 | # TODO: specialized exception, handle it caller-side so the caller | |
105 | # can decide to skip or fail test. | |
106 | raise Exception('Label is no present') | |
107 | marker = _markers[label] | |
108 | constructor = _project_constructor[marker['project']] | |
109 | path = marker['path'] | |
110 | sha1 = marker['sha1'] | |
111 | deps = marker['deps'] | |
112 | ||
113 | # Cache path for the label | |
114 | cache_path = os.path.join(Settings.projects_cache_folder, label) | |
115 | pickle_path = os.path.join(cache_path, label+".pickle") | |
116 | ||
117 | # Check if Pickle Rick is present and valid. If so return it asap. | |
118 | if os.path.exists(pickle_path): | |
119 | with open(pickle_path, 'rb') as pickle_file: | |
120 | pickled = pickle.load(pickle_file) | |
121 | if _validate_pickle(pickled, label): | |
122 | return pickled | |
123 | else: | |
124 | pickled.cleanup() | |
125 | _logger.warn("Pickle for {} is invalid. Rebuilding".format(label)) | |
126 | ||
127 | project = constructor(label, path, sha1, cache_path) | |
128 | ||
129 | for dep in deps: | |
130 | obj_dep = get_precook(dep) | |
131 | project.dependencies[dep] = obj_dep | |
132 | ||
133 | project.autobuild() | |
134 | project._immutable = True | |
135 | with open(pickle_path, 'wb') as pickle_file: | |
136 | pickle.dump(project, pickle_file) | |
137 | ||
138 | return project |