Lachlan pushed to branch lachlan/pickle-yaml-test-list-composite at BuildStream / buildstream
Commits:
-
030935ff
by Jonathan Maw at 2018-10-05T16:39:11Z
-
ae5b554b
by Lachlan Mackenzie at 2018-10-05T16:39:11Z
-
fa7d0e88
by Lachlan Mackenzie at 2018-10-05T16:39:11Z
-
f9e39bdc
by Lachlan Mackenzie at 2018-10-05T16:39:23Z
4 changed files:
- buildstream/_loader/loader.py
- buildstream/_yamlcache.py
- tests/frontend/yamlcache.py
- tests/yaml/yaml.py
Changes:
... | ... | @@ -113,7 +113,13 @@ class Loader(): |
113 | 113 |
profile_start(Topics.LOAD_PROJECT, target)
|
114 | 114 |
junction, name, loader = self._parse_name(target, rewritable, ticker,
|
115 | 115 |
fetch_subprojects=fetch_subprojects)
|
116 |
- with YamlCache.open(self._context) as yaml_cache:
|
|
116 |
+ |
|
117 |
+ # XXX This will need to be changed to the context's top-level project if this method
|
|
118 |
+ # is ever used for subprojects
|
|
119 |
+ top_dir = self.project.directory
|
|
120 |
+ |
|
121 |
+ cache_file = YamlCache.get_cache_file(top_dir)
|
|
122 |
+ with YamlCache.open(self._context, cache_file) as yaml_cache:
|
|
117 | 123 |
loader._load_file(name, rewritable, ticker, fetch_subprojects, yaml_cache)
|
118 | 124 |
deps.append(Dependency(name, junction=junction))
|
119 | 125 |
profile_end(Topics.LOAD_PROJECT, target)
|
... | ... | @@ -54,8 +54,10 @@ class YamlCache(): |
54 | 54 |
self._context = context
|
55 | 55 |
|
56 | 56 |
# Writes the yaml cache to the specified path.
|
57 |
- def write(self):
|
|
58 |
- path = self._get_cache_file(self._context)
|
|
57 |
+ #
|
|
58 |
+ # Args:
|
|
59 |
+ # path (str): The path to the cache file.
|
|
60 |
+ def write(self, path):
|
|
59 | 61 |
parent_dir = os.path.dirname(path)
|
60 | 62 |
os.makedirs(parent_dir, exist_ok=True)
|
61 | 63 |
with open(path, "wb") as f:
|
... | ... | @@ -139,14 +141,14 @@ class YamlCache(): |
139 | 141 |
#
|
140 | 142 |
# Args:
|
141 | 143 |
# context (Context): The context.
|
144 |
+ # cachefile (str): The path to the cache file.
|
|
142 | 145 |
#
|
143 | 146 |
# Returns:
|
144 | 147 |
# (YamlCache): A YamlCache.
|
145 | 148 |
@staticmethod
|
146 | 149 |
@contextmanager
|
147 |
- def open(context):
|
|
150 |
+ def open(context, cachefile):
|
|
148 | 151 |
# Try to load from disk first
|
149 |
- cachefile = YamlCache._get_cache_file(context)
|
|
150 | 152 |
cache = None
|
151 | 153 |
if os.path.exists(cachefile):
|
152 | 154 |
try:
|
... | ... | @@ -155,12 +157,13 @@ class YamlCache(): |
155 | 157 |
except pickle.UnpicklingError as e:
|
156 | 158 |
sys.stderr.write("Failed to load YamlCache, {}\n".format(e))
|
157 | 159 |
|
160 |
+ # Failed to load from disk, create a new one
|
|
158 | 161 |
if not cache:
|
159 | 162 |
cache = YamlCache(context)
|
160 | 163 |
|
161 | 164 |
yield cache
|
162 | 165 |
|
163 |
- cache.write()
|
|
166 |
+ cache.write(cachefile)
|
|
164 | 167 |
|
165 | 168 |
# Calculates a key for putting into the cache.
|
166 | 169 |
@staticmethod
|
... | ... | @@ -170,13 +173,7 @@ class YamlCache(): |
170 | 173 |
|
171 | 174 |
# Retrieves a path to the yaml cache file.
|
172 | 175 |
@staticmethod
|
173 |
- def _get_cache_file(context):
|
|
174 |
- try:
|
|
175 |
- toplevel_project = context.get_toplevel_project()
|
|
176 |
- top_dir = toplevel_project.directory
|
|
177 |
- except IndexError:
|
|
178 |
- # Context has no projects, fall back to current directory
|
|
179 |
- top_dir = os.getcwd()
|
|
176 |
+ def get_cache_file(top_dir):
|
|
180 | 177 |
return os.path.join(top_dir, ".bst", YAML_CACHE_FILENAME)
|
181 | 178 |
|
182 | 179 |
|
... | ... | @@ -52,7 +52,8 @@ def generate_project(tmpdir, ref_storage, with_junction, name="test"): |
52 | 52 |
def with_yamlcache(project_dir):
|
53 | 53 |
context = Context()
|
54 | 54 |
project = Project(project_dir, context)
|
55 |
- with YamlCache.open(context) as yamlcache:
|
|
55 |
+ cache_file = YamlCache.get_cache_file(project_dir)
|
|
56 |
+ with YamlCache.open(context, cache_file) as yamlcache:
|
|
56 | 57 |
yield yamlcache, project
|
57 | 58 |
|
58 | 59 |
|
... | ... | @@ -62,12 +63,12 @@ def yamlcache_key(yamlcache, in_file, copy_tree=False): |
62 | 63 |
return key
|
63 | 64 |
|
64 | 65 |
|
65 |
-def modified_file(input_file):
|
|
66 |
+def modified_file(input_file, tmpdir):
|
|
66 | 67 |
with open(input_file) as f:
|
67 | 68 |
data = f.read()
|
68 | 69 |
assert 'variables' not in data
|
69 | 70 |
data += '\nvariables: {modified: True}\n'
|
70 |
- _, temppath = tempfile.mkstemp(text=True)
|
|
71 |
+ _, temppath = tempfile.mkstemp(dir=tmpdir, text=True)
|
|
71 | 72 |
with open(temppath, 'w') as f:
|
72 | 73 |
f.write(data)
|
73 | 74 |
|
... | ... | @@ -96,7 +97,7 @@ def test_yamlcache_used(cli, tmpdir, ref_storage, with_junction, move_project): |
96 | 97 |
# *Absolutely* horrible cache corruption to check it's being used
|
97 | 98 |
# Modifying the data from the cache is fraught with danger,
|
98 | 99 |
# so instead I'll load a modified version of the original file
|
99 |
- temppath = modified_file(element_path)
|
|
100 |
+ temppath = modified_file(element_path, str(tmpdir))
|
|
100 | 101 |
contents = _yaml.load(temppath, copy_tree=False, project=prj)
|
101 | 102 |
key = yamlcache_key(yc, element_path)
|
102 | 103 |
yc.put(prj, element_path, key, contents)
|
1 | 1 |
import os
|
2 | 2 |
import pytest
|
3 |
+import tempfile
|
|
3 | 4 |
from collections import Mapping
|
4 | 5 |
|
5 | 6 |
from buildstream import _yaml
|
6 | 7 |
from buildstream._exceptions import LoadError, LoadErrorReason
|
8 |
+from buildstream._context import Context
|
|
9 |
+from buildstream._yamlcache import YamlCache
|
|
7 | 10 |
|
8 | 11 |
DATA_DIR = os.path.join(
|
9 | 12 |
os.path.dirname(os.path.realpath(__file__)),
|
... | ... | @@ -150,6 +153,22 @@ def test_composite_preserve_originals(datafiles): |
150 | 153 |
assert(_yaml.node_get(orig_extra, str, 'old') == 'new')
|
151 | 154 |
|
152 | 155 |
|
156 |
+def load_yaml_file(filename, *, cache_path, shortname=None, from_cache='raw'):
|
|
157 |
+ |
|
158 |
+ temppath = tempfile.mkstemp(dir=str(cache_path), text=True)
|
|
159 |
+ context = Context()
|
|
160 |
+ |
|
161 |
+ with YamlCache.open(context, str(temppath)) as yc:
|
|
162 |
+ if from_cache == 'raw':
|
|
163 |
+ return _yaml.load(filename, shortname)
|
|
164 |
+ elif from_cache == 'cached':
|
|
165 |
+ _yaml.load(filename, shortname)
|
|
166 |
+ |
|
167 |
+ return _yaml.load(filename, shortname, yaml_cache=yc)
|
|
168 |
+ else:
|
|
169 |
+ assert False
|
|
170 |
+ |
|
171 |
+ |
|
153 | 172 |
# Tests for list composition
|
154 | 173 |
#
|
155 | 174 |
# Each test composits a filename on top of basics.yaml, and tests
|
... | ... | @@ -165,6 +184,7 @@ def test_composite_preserve_originals(datafiles): |
165 | 184 |
# prov_col: The expected provenance column of "mood"
|
166 | 185 |
#
|
167 | 186 |
@pytest.mark.datafiles(os.path.join(DATA_DIR))
|
187 |
+@pytest.mark.parametrize('caching', [('raw'), ('cached')])
|
|
168 | 188 |
@pytest.mark.parametrize("filename,index,length,mood,prov_file,prov_line,prov_col", [
|
169 | 189 |
|
170 | 190 |
# Test results of compositing with the (<) prepend directive
|
... | ... | @@ -195,14 +215,15 @@ def test_composite_preserve_originals(datafiles): |
195 | 215 |
('implicitoverwrite.yaml', 0, 2, 'overwrite1', 'implicitoverwrite.yaml', 4, 8),
|
196 | 216 |
('implicitoverwrite.yaml', 1, 2, 'overwrite2', 'implicitoverwrite.yaml', 6, 8),
|
197 | 217 |
])
|
198 |
-def test_list_composition(datafiles, filename,
|
|
218 |
+def test_list_composition(datafiles, filename, tmpdir,
|
|
199 | 219 |
index, length, mood,
|
200 |
- prov_file, prov_line, prov_col):
|
|
201 |
- base = os.path.join(datafiles.dirname, datafiles.basename, 'basics.yaml')
|
|
202 |
- overlay = os.path.join(datafiles.dirname, datafiles.basename, filename)
|
|
220 |
+ prov_file, prov_line, prov_col, caching):
|
|
221 |
+ base_file = os.path.join(datafiles.dirname, datafiles.basename, 'basics.yaml')
|
|
222 |
+ overlay_file = os.path.join(datafiles.dirname, datafiles.basename, filename)
|
|
223 |
+ |
|
224 |
+ base = load_yaml_file(base_file, cache_path=tmpdir, shortname='basics.yaml', from_cache=caching)
|
|
225 |
+ overlay = load_yaml_file(overlay_file, cache_path=tmpdir, shortname=filename, from_cache=caching)
|
|
203 | 226 |
|
204 |
- base = _yaml.load(base, shortname='basics.yaml')
|
|
205 |
- overlay = _yaml.load(overlay, shortname=filename)
|
|
206 | 227 |
_yaml.composite_dict(base, overlay)
|
207 | 228 |
|
208 | 229 |
children = _yaml.node_get(base, list, 'children')
|
... | ... | @@ -254,6 +275,7 @@ def test_list_deletion(datafiles): |
254 | 275 |
# prov_col: The expected provenance column of "mood"
|
255 | 276 |
#
|
256 | 277 |
@pytest.mark.datafiles(os.path.join(DATA_DIR))
|
278 |
+@pytest.mark.parametrize('caching', [('raw'), ('cached')])
|
|
257 | 279 |
@pytest.mark.parametrize("filename1,filename2,index,length,mood,prov_file,prov_line,prov_col", [
|
258 | 280 |
|
259 | 281 |
# Test results of compositing literal list with (>) and then (<)
|
... | ... | @@ -310,9 +332,9 @@ def test_list_deletion(datafiles): |
310 | 332 |
('listoverwrite.yaml', 'listprepend.yaml', 2, 4, 'overwrite1', 'listoverwrite.yaml', 5, 10),
|
311 | 333 |
('listoverwrite.yaml', 'listprepend.yaml', 3, 4, 'overwrite2', 'listoverwrite.yaml', 7, 10),
|
312 | 334 |
])
|
313 |
-def test_list_composition_twice(datafiles, filename1, filename2,
|
|
335 |
+def test_list_composition_twice(datafiles, tmpdir, filename1, filename2,
|
|
314 | 336 |
index, length, mood,
|
315 |
- prov_file, prov_line, prov_col):
|
|
337 |
+ prov_file, prov_line, prov_col, caching):
|
|
316 | 338 |
file_base = os.path.join(datafiles.dirname, datafiles.basename, 'basics.yaml')
|
317 | 339 |
file1 = os.path.join(datafiles.dirname, datafiles.basename, filename1)
|
318 | 340 |
file2 = os.path.join(datafiles.dirname, datafiles.basename, filename2)
|
... | ... | @@ -320,9 +342,9 @@ def test_list_composition_twice(datafiles, filename1, filename2, |
320 | 342 |
#####################
|
321 | 343 |
# Round 1 - Fight !
|
322 | 344 |
#####################
|
323 |
- base = _yaml.load(file_base, shortname='basics.yaml')
|
|
324 |
- overlay1 = _yaml.load(file1, shortname=filename1)
|
|
325 |
- overlay2 = _yaml.load(file2, shortname=filename2)
|
|
345 |
+ base = load_yaml_file(file_base, cache_path=tmpdir, shortname='basics.yaml', from_cache=caching)
|
|
346 |
+ overlay1 = load_yaml_file(file1, cache_path=tmpdir, shortname=filename1, from_cache=caching)
|
|
347 |
+ overlay2 = load_yaml_file(file2, cache_path=tmpdir, shortname=filename2, from_cache=caching)
|
|
326 | 348 |
|
327 | 349 |
_yaml.composite_dict(base, overlay1)
|
328 | 350 |
_yaml.composite_dict(base, overlay2)
|
... | ... | @@ -337,9 +359,9 @@ def test_list_composition_twice(datafiles, filename1, filename2, |
337 | 359 |
#####################
|
338 | 360 |
# Round 2 - Fight !
|
339 | 361 |
#####################
|
340 |
- base = _yaml.load(file_base, shortname='basics.yaml')
|
|
341 |
- overlay1 = _yaml.load(file1, shortname=filename1)
|
|
342 |
- overlay2 = _yaml.load(file2, shortname=filename2)
|
|
362 |
+ base = load_yaml_file(file_base, cache_path=tmpdir, shortname='basics.yaml', from_cache=caching)
|
|
363 |
+ overlay1 = load_yaml_file(file1, cache_path=tmpdir, shortname=filename1, from_cache=caching)
|
|
364 |
+ overlay2 = load_yaml_file(file2, cache_path=tmpdir, shortname=filename2, from_cache=caching)
|
|
343 | 365 |
|
344 | 366 |
_yaml.composite_dict(overlay1, overlay2)
|
345 | 367 |
_yaml.composite_dict(base, overlay1)
|