Javier Jardón pushed to branch jjardon/fedora_29 at BuildStream / buildstream
Commits:
-
1ee4a4ba
by Abderrahim Kitouni at 2019-02-08T16:42:23Z
-
24c0de16
by Abderrahim Kitouni at 2019-02-08T16:42:23Z
-
a937f99a
by Javier Jardón at 2019-02-08T20:29:05Z
-
da1560e4
by Javier Jardón at 2019-02-09T09:10:01Z
-
79fbab61
by Jürg Billeter at 2019-02-09T10:30:20Z
-
354c563d
by Jürg Billeter at 2019-02-10T20:03:46Z
-
5e1be71f
by Jürg Billeter at 2019-02-11T05:10:56Z
-
99e1be45
by Jürg Billeter at 2019-02-11T05:12:25Z
-
f95e222e
by Jürg Billeter at 2019-02-11T05:12:25Z
-
89973fb3
by Jürg Billeter at 2019-02-11T05:12:25Z
-
d1da3fb0
by Jürg Billeter at 2019-02-11T05:12:25Z
-
7cf67ed3
by Jürg Billeter at 2019-02-11T05:12:25Z
-
7ec0bb5e
by Jürg Billeter at 2019-02-11T05:44:20Z
-
c07cc967
by Jürg Billeter at 2019-02-11T07:13:28Z
-
9e3d3e05
by Angelos Evripiotis at 2019-02-11T07:14:50Z
-
bb6a692d
by Jürg Billeter at 2019-02-11T09:20:34Z
-
1ed63e54
by Angelos Evripiotis at 2019-02-11T09:24:48Z
-
02e48209
by Angelos Evripiotis at 2019-02-11T09:24:48Z
-
4336e3bf
by Angelos Evripiotis at 2019-02-11T09:24:48Z
-
3f6c5000
by Angelos Evripiotis at 2019-02-11T09:24:48Z
-
adde0c94
by Angelos Evripiotis at 2019-02-11T09:24:48Z
-
a66f8379
by Jürg Billeter at 2019-02-11T13:52:54Z
-
48c0a59b
by Javier Jardón at 2019-02-11T16:23:48Z
12 changed files:
- .gitlab-ci.yml
- CONTRIBUTING.rst
- buildstream/_artifactcache.py
- buildstream/_includes.py
- buildstream/_project.py
- buildstream/plugins/elements/import.py
- buildstream/plugins/sources/local.py
- buildstream/sandbox/sandbox.py
- buildstream/storage/_casbaseddirectory.py
- buildstream/utils.py
- tests/format/include.py
- tests/sources/local.py
Changes:
... | ... | @@ -49,14 +49,14 @@ tests-debian-9: |
49 | 49 |
image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-debian:9-master-46405991
|
50 | 50 |
<<: *tests
|
51 | 51 |
|
52 |
-tests-fedora-27:
|
|
53 |
- image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:27-master-46405991
|
|
54 |
- <<: *tests
|
|
55 |
- |
|
56 | 52 |
tests-fedora-28:
|
57 | 53 |
image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:28-master-46405991
|
58 | 54 |
<<: *tests
|
59 | 55 |
|
56 |
+tests-fedora-29:
|
|
57 |
+ image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:29-jjardon-fedora29-46745295
|
|
58 |
+ <<: *tests
|
|
59 |
+ |
|
60 | 60 |
tests-ubuntu-18.04:
|
61 | 61 |
image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-ubuntu:18.04-master-46405991
|
62 | 62 |
<<: *tests
|
... | ... | @@ -75,8 +75,8 @@ tests-centos-7.6: |
75 | 75 |
<<: *tests
|
76 | 76 |
image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-centos:7.6.1810-master-46405991
|
77 | 77 |
|
78 |
-overnight-fedora-28-aarch64:
|
|
79 |
- image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:aarch64-28-master-46405991
|
|
78 |
+overnight-fedora-29-aarch64:
|
|
79 |
+ image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:aarch64-29-master-46405991
|
|
80 | 80 |
tags:
|
81 | 81 |
- aarch64
|
82 | 82 |
<<: *tests
|
... | ... | @@ -95,7 +95,7 @@ overnight-fedora-28-aarch64: |
95 | 95 |
tests-unix:
|
96 | 96 |
# Use fedora here, to a) run a test on fedora and b) ensure that we
|
97 | 97 |
# can get rid of ostree - this is not possible with debian-8
|
98 |
- image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:27-master-46405991
|
|
98 |
+ image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:29-jjardon-fedora29-46745295
|
|
99 | 99 |
<<: *tests
|
100 | 100 |
variables:
|
101 | 101 |
BST_FORCE_BACKEND: "unix"
|
... | ... | @@ -113,7 +113,7 @@ tests-unix: |
113 | 113 |
|
114 | 114 |
tests-fedora-missing-deps:
|
115 | 115 |
# Ensure that tests behave nicely while missing bwrap and ostree
|
116 |
- image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:28-master-46405991
|
|
116 |
+ image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:29-jjardon-fedora29-46745295
|
|
117 | 117 |
<<: *tests
|
118 | 118 |
|
119 | 119 |
script:
|
... | ... | @@ -132,7 +132,7 @@ tests-fedora-update-deps: |
132 | 132 |
# Check if the tests pass after updating requirements to their latest
|
133 | 133 |
# allowed version.
|
134 | 134 |
allow_failure: true
|
135 |
- image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:28-master-46405991
|
|
135 |
+ image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:29-jjardon-fedora29-46745295
|
|
136 | 136 |
<<: *tests
|
137 | 137 |
|
138 | 138 |
script:
|
... | ... | @@ -291,8 +291,8 @@ coverage: |
291 | 291 |
- cp -a .coverage-reports/ ./coverage-report
|
292 | 292 |
dependencies:
|
293 | 293 |
- tests-debian-9
|
294 |
- - tests-fedora-27
|
|
295 | 294 |
- tests-fedora-28
|
295 |
+ - tests-fedora-29
|
|
296 | 296 |
- tests-fedora-missing-deps
|
297 | 297 |
- tests-ubuntu-18.04
|
298 | 298 |
- tests-unix
|
... | ... | @@ -1707,26 +1707,13 @@ You can then analyze the results interactively using the 'pstats' module: |
1707 | 1707 |
For more detailed documentation of cProfile and 'pstats', see:
|
1708 | 1708 |
https://docs.python.org/3/library/profile.html.
|
1709 | 1709 |
|
1710 |
-For a richer visualisation of the callstack you can try `Pyflame
|
|
1711 |
-<https://github.com/uber/pyflame>`_. Once you have followed the instructions in
|
|
1712 |
-Pyflame's README to install the tool, you can profile `bst` commands as in the
|
|
1713 |
-following example:
|
|
1710 |
+For a richer and interactive visualisation of the `.cprofile` files, you can
|
|
1711 |
+try `snakeviz <http://jiffyclub.github.io/snakeviz/#interpreting-results>`_.
|
|
1712 |
+You can install it with `pip install snakeviz`. Here is an example invocation:
|
|
1714 | 1713 |
|
1715 |
- pyflame --output bst.flame --trace bst --help
|
|
1716 |
- |
|
1717 |
-You may see an `Unexpected ptrace(2) exception:` error. Note that the `bst`
|
|
1718 |
-operation will continue running in the background in this case, you will need
|
|
1719 |
-to wait for it to complete or kill it. Once this is done, rerun the above
|
|
1720 |
-command which appears to fix the issue.
|
|
1721 |
- |
|
1722 |
-Once you have output from pyflame, you can use the ``flamegraph.pl`` script
|
|
1723 |
-from the `Flamegraph project <https://github.com/brendangregg/FlameGraph>`_
|
|
1724 |
-to generate an .svg image:
|
|
1725 |
- |
|
1726 |
- ./flamegraph.pl bst.flame > bst-flamegraph.svg
|
|
1727 |
- |
|
1728 |
-The generated SVG file can then be viewed in your preferred web browser.
|
|
1714 |
+ snakeviz bst.cprofile
|
|
1729 | 1715 |
|
1716 |
+It will then start a webserver and launch a browser to the relevant page.
|
|
1730 | 1717 |
|
1731 | 1718 |
Profiling specific parts of BuildStream with BST_PROFILE
|
1732 | 1719 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
... | ... | @@ -467,7 +467,7 @@ class ArtifactCache(): |
467 | 467 |
# on_failure (callable): Called if we fail to contact one of the caches.
|
468 | 468 |
#
|
469 | 469 |
def initialize_remotes(self, *, on_failure=None):
|
470 |
- remote_specs = self.global_remote_specs
|
|
470 |
+ remote_specs = list(self.global_remote_specs)
|
|
471 | 471 |
|
472 | 472 |
for project in self.project_remote_specs:
|
473 | 473 |
remote_specs += self.project_remote_specs[project]
|
... | ... | @@ -1046,8 +1046,5 @@ class ArtifactCache(): |
1046 | 1046 |
# A list of ArtifactCacheSpec instances describing the remote artifact caches.
|
1047 | 1047 |
#
|
1048 | 1048 |
def _configured_remote_artifact_cache_specs(context, project):
|
1049 |
- project_overrides = context.get_overrides(project.name)
|
|
1050 |
- project_extra_specs = ArtifactCache.specs_from_config_node(project_overrides)
|
|
1051 |
- |
|
1052 | 1049 |
return list(utils._deduplicate(
|
1053 |
- project_extra_specs + project.artifact_cache_specs + context.artifact_cache_specs))
|
|
1050 |
+ project.artifact_cache_specs + context.artifact_cache_specs))
|
... | ... | @@ -40,19 +40,34 @@ class Includes: |
40 | 40 |
includes = [_yaml.node_get(node, str, '(@)')]
|
41 | 41 |
else:
|
42 | 42 |
includes = _yaml.node_get(node, list, '(@)', default_value=None)
|
43 |
+ |
|
44 |
+ include_provenance = None
|
|
43 | 45 |
if '(@)' in node:
|
46 |
+ include_provenance = _yaml.node_get_provenance(node, key='(@)')
|
|
44 | 47 |
del node['(@)']
|
45 | 48 |
|
46 | 49 |
if includes:
|
47 | 50 |
for include in reversed(includes):
|
48 | 51 |
if only_local and ':' in include:
|
49 | 52 |
continue
|
50 |
- include_node, file_path, sub_loader = self._include_file(include,
|
|
51 |
- current_loader)
|
|
53 |
+ try:
|
|
54 |
+ include_node, file_path, sub_loader = self._include_file(include,
|
|
55 |
+ current_loader)
|
|
56 |
+ except LoadError as e:
|
|
57 |
+ if e.reason == LoadErrorReason.MISSING_FILE:
|
|
58 |
+ message = "{}: Include block references a file that could not be found: '{}'.".format(
|
|
59 |
+ include_provenance, include)
|
|
60 |
+ raise LoadError(LoadErrorReason.MISSING_FILE, message) from e
|
|
61 |
+ elif e.reason == LoadErrorReason.LOADING_DIRECTORY:
|
|
62 |
+ message = "{}: Include block references a directory instead of a file: '{}'.".format(
|
|
63 |
+ include_provenance, include)
|
|
64 |
+ raise LoadError(LoadErrorReason.LOADING_DIRECTORY, message) from e
|
|
65 |
+ else:
|
|
66 |
+ raise
|
|
67 |
+ |
|
52 | 68 |
if file_path in included:
|
53 |
- provenance = _yaml.node_get_provenance(node)
|
|
54 | 69 |
raise LoadError(LoadErrorReason.RECURSIVE_INCLUDE,
|
55 |
- "{}: trying to recursively include {}". format(provenance,
|
|
70 |
+ "{}: trying to recursively include {}". format(include_provenance,
|
|
56 | 71 |
file_path))
|
57 | 72 |
# Because the included node will be modified, we need
|
58 | 73 |
# to copy it so that we do not modify the toplevel
|
... | ... | @@ -101,7 +116,7 @@ class Includes: |
101 | 116 |
file_path = os.path.join(directory, include)
|
102 | 117 |
key = (current_loader, file_path)
|
103 | 118 |
if key not in self._loaded:
|
104 |
- self._loaded[key] = _yaml.load(os.path.join(directory, include),
|
|
119 |
+ self._loaded[key] = _yaml.load(file_path,
|
|
105 | 120 |
shortname=shortname,
|
106 | 121 |
project=project,
|
107 | 122 |
copy_tree=self._copy_tree)
|
... | ... | @@ -549,7 +549,15 @@ class Project(): |
549 | 549 |
#
|
550 | 550 |
|
551 | 551 |
# Load artifacts pull/push configuration for this project
|
552 |
- self.artifact_cache_specs = ArtifactCache.specs_from_config_node(config, self.directory)
|
|
552 |
+ project_specs = ArtifactCache.specs_from_config_node(config, self.directory)
|
|
553 |
+ override_specs = ArtifactCache.specs_from_config_node(
|
|
554 |
+ self._context.get_overrides(self.name), self.directory)
|
|
555 |
+ |
|
556 |
+ self.artifact_cache_specs = override_specs + project_specs
|
|
557 |
+ |
|
558 |
+ if self.junction:
|
|
559 |
+ parent = self.junction._get_project()
|
|
560 |
+ self.artifact_cache_specs = parent.artifact_cache_specs + self.artifact_cache_specs
|
|
553 | 561 |
|
554 | 562 |
# Load remote-execution configuration for this project
|
555 | 563 |
project_specs = SandboxRemote.specs_from_config_node(config, self.directory)
|
... | ... | @@ -42,6 +42,10 @@ class ImportElement(Element): |
42 | 42 |
BST_VIRTUAL_DIRECTORY = True
|
43 | 43 |
|
44 | 44 |
def configure(self, node):
|
45 |
+ self.node_validate(node, [
|
|
46 |
+ 'source', 'target'
|
|
47 |
+ ])
|
|
48 |
+ |
|
45 | 49 |
self.source = self.node_subst_member(node, 'source')
|
46 | 50 |
self.target = self.node_subst_member(node, 'target')
|
47 | 51 |
|
... | ... | @@ -97,7 +97,7 @@ class LocalSource(Source): |
97 | 97 |
with self.timed_activity("Staging local files at {}".format(self.path)):
|
98 | 98 |
|
99 | 99 |
if os.path.isdir(self.fullpath):
|
100 |
- files = list(utils.list_relative_paths(self.fullpath, list_dirs=True))
|
|
100 |
+ files = list(utils.list_relative_paths(self.fullpath))
|
|
101 | 101 |
utils.copy_files(self.fullpath, directory, files=files)
|
102 | 102 |
else:
|
103 | 103 |
destfile = os.path.join(directory, os.path.basename(self.path))
|
... | ... | @@ -133,11 +133,11 @@ def unique_key(filename): |
133 | 133 |
|
134 | 134 |
# Return some hard coded things for files which
|
135 | 135 |
# have no content to calculate a key for
|
136 |
- if os.path.isdir(filename):
|
|
137 |
- return "0"
|
|
138 |
- elif os.path.islink(filename):
|
|
136 |
+ if os.path.islink(filename):
|
|
139 | 137 |
# For a symbolic link, use the link target as its unique identifier
|
140 | 138 |
return os.readlink(filename)
|
139 |
+ elif os.path.isdir(filename):
|
|
140 |
+ return "0"
|
|
141 | 141 |
|
142 | 142 |
return utils.sha256sum(filename)
|
143 | 143 |
|
... | ... | @@ -525,11 +525,11 @@ class Sandbox(): |
525 | 525 |
# (bool): Whether a command exists inside the sandbox.
|
526 | 526 |
def _has_command(self, command, env=None):
|
527 | 527 |
if os.path.isabs(command):
|
528 |
- return os.path.exists(os.path.join(
|
|
528 |
+ return os.path.lexists(os.path.join(
|
|
529 | 529 |
self._root, command.lstrip(os.sep)))
|
530 | 530 |
|
531 | 531 |
for path in env.get('PATH').split(':'):
|
532 |
- if os.path.exists(os.path.join(
|
|
532 |
+ if os.path.lexists(os.path.join(
|
|
533 | 533 |
self._root, path.lstrip(os.sep), command)):
|
534 | 534 |
return True
|
535 | 535 |
|
... | ... | @@ -795,24 +795,11 @@ class CasBasedDirectory(Directory): |
795 | 795 |
Return value: List(str) - list of all paths
|
796 | 796 |
"""
|
797 | 797 |
|
798 |
- symlink_list = filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.SymlinkNode),
|
|
799 |
- self.index.items())
|
|
800 |
- file_list = list(filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.FileNode),
|
|
798 |
+ file_list = list(filter(lambda i: not isinstance(i[1].buildstream_object, CasBasedDirectory),
|
|
801 | 799 |
self.index.items()))
|
802 | 800 |
directory_list = filter(lambda i: isinstance(i[1].buildstream_object, CasBasedDirectory),
|
803 | 801 |
self.index.items())
|
804 | 802 |
|
805 |
- # We need to mimic the behaviour of os.walk, in which symlinks
|
|
806 |
- # to directories count as directories and symlinks to file or
|
|
807 |
- # broken symlinks count as files. os.walk doesn't follow
|
|
808 |
- # symlinks, so we don't recurse.
|
|
809 |
- for (k, v) in sorted(symlink_list):
|
|
810 |
- target = self._resolve(k, absolute_symlinks_resolve=True)
|
|
811 |
- if isinstance(target, CasBasedDirectory):
|
|
812 |
- yield os.path.join(relpath, k)
|
|
813 |
- else:
|
|
814 |
- file_list.append((k, v))
|
|
815 |
- |
|
816 | 803 |
if file_list == [] and relpath != "":
|
817 | 804 |
yield relpath
|
818 | 805 |
else:
|
... | ... | @@ -111,7 +111,7 @@ class FileListResult(): |
111 | 111 |
return ret
|
112 | 112 |
|
113 | 113 |
|
114 |
-def list_relative_paths(directory, *, list_dirs=True):
|
|
114 |
+def list_relative_paths(directory):
|
|
115 | 115 |
"""A generator for walking directory relative paths
|
116 | 116 |
|
117 | 117 |
This generator is useful for checking the full manifest of
|
... | ... | @@ -125,13 +125,26 @@ def list_relative_paths(directory, *, list_dirs=True): |
125 | 125 |
|
126 | 126 |
Args:
|
127 | 127 |
directory (str): The directory to list files in
|
128 |
- list_dirs (bool): Whether to list directories
|
|
129 | 128 |
|
130 | 129 |
Yields:
|
131 | 130 |
Relative filenames in `directory`
|
132 | 131 |
"""
|
133 | 132 |
for (dirpath, dirnames, filenames) in os.walk(directory):
|
134 | 133 |
|
134 |
+ # os.walk does not decend into symlink directories, which
|
|
135 |
+ # makes sense because otherwise we might have redundant
|
|
136 |
+ # directories, or end up descending into directories outside
|
|
137 |
+ # of the walk() directory.
|
|
138 |
+ #
|
|
139 |
+ # But symlinks to directories are still identified as
|
|
140 |
+ # subdirectories in the walked `dirpath`, so we extract
|
|
141 |
+ # these symlinks from `dirnames` and add them to `filenames`.
|
|
142 |
+ #
|
|
143 |
+ for d in dirnames:
|
|
144 |
+ fullpath = os.path.join(dirpath, d)
|
|
145 |
+ if os.path.islink(fullpath):
|
|
146 |
+ filenames.append(d)
|
|
147 |
+ |
|
135 | 148 |
# Modifying the dirnames directly ensures that the os.walk() generator
|
136 | 149 |
# allows us to specify the order in which they will be iterated.
|
137 | 150 |
dirnames.sort()
|
... | ... | @@ -143,25 +156,10 @@ def list_relative_paths(directory, *, list_dirs=True): |
143 | 156 |
# `directory`, prefer to have no prefix in that case.
|
144 | 157 |
basepath = relpath if relpath != '.' and dirpath != directory else ''
|
145 | 158 |
|
146 |
- # os.walk does not decend into symlink directories, which
|
|
147 |
- # makes sense because otherwise we might have redundant
|
|
148 |
- # directories, or end up descending into directories outside
|
|
149 |
- # of the walk() directory.
|
|
150 |
- #
|
|
151 |
- # But symlinks to directories are still identified as
|
|
152 |
- # subdirectories in the walked `dirpath`, so we extract
|
|
153 |
- # these symlinks from `dirnames`
|
|
154 |
- #
|
|
155 |
- if list_dirs:
|
|
156 |
- for d in dirnames:
|
|
157 |
- fullpath = os.path.join(dirpath, d)
|
|
158 |
- if os.path.islink(fullpath):
|
|
159 |
- yield os.path.join(basepath, d)
|
|
160 |
- |
|
161 | 159 |
# We've decended into an empty directory, in this case we
|
162 | 160 |
# want to include the directory itself, but not in any other
|
163 | 161 |
# case.
|
164 |
- if list_dirs and not filenames:
|
|
162 |
+ if not filenames:
|
|
165 | 163 |
yield relpath
|
166 | 164 |
|
167 | 165 |
# List the filenames in the walked directory
|
1 | 1 |
import os
|
2 |
+import textwrap
|
|
2 | 3 |
import pytest
|
3 | 4 |
from buildstream import _yaml
|
4 | 5 |
from buildstream._exceptions import ErrorDomain, LoadErrorReason
|
... | ... | @@ -27,6 +28,46 @@ def test_include_project_file(cli, datafiles): |
27 | 28 |
assert loaded['included'] == 'True'
|
28 | 29 |
|
29 | 30 |
|
31 |
+def test_include_missing_file(cli, tmpdir):
|
|
32 |
+ tmpdir.join('project.conf').write('{"name": "test"}')
|
|
33 |
+ element = tmpdir.join('include_missing_file.bst')
|
|
34 |
+ |
|
35 |
+ # Normally we would use dicts and _yaml.dump to write such things, but here
|
|
36 |
+ # we want to be sure of a stable line and column number.
|
|
37 |
+ element.write(textwrap.dedent("""
|
|
38 |
+ kind: manual
|
|
39 |
+ |
|
40 |
+ "(@)":
|
|
41 |
+ - nosuch.yaml
|
|
42 |
+ """).strip())
|
|
43 |
+ |
|
44 |
+ result = cli.run(project=str(tmpdir), args=['show', str(element.basename)])
|
|
45 |
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
|
|
46 |
+ # Make sure the root cause provenance is in the output.
|
|
47 |
+ assert 'line 4 column 2' in result.stderr
|
|
48 |
+ |
|
49 |
+ |
|
50 |
+def test_include_dir(cli, tmpdir):
|
|
51 |
+ tmpdir.join('project.conf').write('{"name": "test"}')
|
|
52 |
+ tmpdir.mkdir('subdir')
|
|
53 |
+ element = tmpdir.join('include_dir.bst')
|
|
54 |
+ |
|
55 |
+ # Normally we would use dicts and _yaml.dump to write such things, but here
|
|
56 |
+ # we want to be sure of a stable line and column number.
|
|
57 |
+ element.write(textwrap.dedent("""
|
|
58 |
+ kind: manual
|
|
59 |
+ |
|
60 |
+ "(@)":
|
|
61 |
+ - subdir/
|
|
62 |
+ """).strip())
|
|
63 |
+ |
|
64 |
+ result = cli.run(project=str(tmpdir), args=['show', str(element.basename)])
|
|
65 |
+ result.assert_main_error(
|
|
66 |
+ ErrorDomain.LOAD, LoadErrorReason.LOADING_DIRECTORY)
|
|
67 |
+ # Make sure the root cause provenance is in the output.
|
|
68 |
+ assert 'line 4 column 2' in result.stderr
|
|
69 |
+ |
|
70 |
+ |
|
30 | 71 |
@pytest.mark.datafiles(DATA_DIR)
|
31 | 72 |
def test_include_junction_file(cli, tmpdir, datafiles):
|
32 | 73 |
project = os.path.join(str(datafiles), 'junction')
|
... | ... | @@ -47,7 +88,7 @@ def test_include_junction_file(cli, tmpdir, datafiles): |
47 | 88 |
|
48 | 89 |
|
49 | 90 |
@pytest.mark.datafiles(DATA_DIR)
|
50 |
-def test_include_junction_options(cli, tmpdir, datafiles):
|
|
91 |
+def test_include_junction_options(cli, datafiles):
|
|
51 | 92 |
project = os.path.join(str(datafiles), 'options')
|
52 | 93 |
|
53 | 94 |
result = cli.run(project=project, args=[
|
... | ... | @@ -128,7 +169,7 @@ def test_junction_element_not_partial_project_file(cli, tmpdir, datafiles): |
128 | 169 |
|
129 | 170 |
|
130 | 171 |
@pytest.mark.datafiles(DATA_DIR)
|
131 |
-def test_include_element_overrides(cli, tmpdir, datafiles):
|
|
172 |
+def test_include_element_overrides(cli, datafiles):
|
|
132 | 173 |
project = os.path.join(str(datafiles), 'overrides')
|
133 | 174 |
|
134 | 175 |
result = cli.run(project=project, args=[
|
... | ... | @@ -143,7 +184,7 @@ def test_include_element_overrides(cli, tmpdir, datafiles): |
143 | 184 |
|
144 | 185 |
|
145 | 186 |
@pytest.mark.datafiles(DATA_DIR)
|
146 |
-def test_include_element_overrides_composition(cli, tmpdir, datafiles):
|
|
187 |
+def test_include_element_overrides_composition(cli, datafiles):
|
|
147 | 188 |
project = os.path.join(str(datafiles), 'overrides')
|
148 | 189 |
|
149 | 190 |
result = cli.run(project=project, args=[
|
... | ... | @@ -158,7 +199,7 @@ def test_include_element_overrides_composition(cli, tmpdir, datafiles): |
158 | 199 |
|
159 | 200 |
|
160 | 201 |
@pytest.mark.datafiles(DATA_DIR)
|
161 |
-def test_include_element_overrides_sub_include(cli, tmpdir, datafiles):
|
|
202 |
+def test_include_element_overrides_sub_include(cli, datafiles):
|
|
162 | 203 |
project = os.path.join(str(datafiles), 'sub-include')
|
163 | 204 |
|
164 | 205 |
result = cli.run(project=project, args=[
|
... | ... | @@ -192,7 +233,7 @@ def test_junction_do_not_use_included_overrides(cli, tmpdir, datafiles): |
192 | 233 |
|
193 | 234 |
|
194 | 235 |
@pytest.mark.datafiles(DATA_DIR)
|
195 |
-def test_conditional_in_fragment(cli, tmpdir, datafiles):
|
|
236 |
+def test_conditional_in_fragment(cli, datafiles):
|
|
196 | 237 |
project = os.path.join(str(datafiles), 'conditional')
|
197 | 238 |
|
198 | 239 |
result = cli.run(project=project, args=[
|
... | ... | @@ -222,7 +263,7 @@ def test_inner(cli, datafiles): |
222 | 263 |
|
223 | 264 |
|
224 | 265 |
@pytest.mark.datafiles(DATA_DIR)
|
225 |
-def test_recusive_include(cli, tmpdir, datafiles):
|
|
266 |
+def test_recursive_include(cli, datafiles):
|
|
226 | 267 |
project = os.path.join(str(datafiles), 'recursive')
|
227 | 268 |
|
228 | 269 |
result = cli.run(project=project, args=[
|
... | ... | @@ -231,6 +272,7 @@ def test_recusive_include(cli, tmpdir, datafiles): |
231 | 272 |
'--format', '%{vars}',
|
232 | 273 |
'element.bst'])
|
233 | 274 |
result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.RECURSIVE_INCLUDE)
|
275 |
+ assert 'line 2 column 2' in result.stderr
|
|
234 | 276 |
|
235 | 277 |
|
236 | 278 |
@pytest.mark.datafiles(DATA_DIR)
|
... | ... | @@ -136,3 +136,23 @@ def test_stage_file_exists(cli, tmpdir, datafiles): |
136 | 136 |
result = cli.run(project=project, args=['build', 'target.bst'])
|
137 | 137 |
result.assert_main_error(ErrorDomain.STREAM, None)
|
138 | 138 |
result.assert_task_error(ErrorDomain.SOURCE, 'ensure-stage-dir-fail')
|
139 |
+ |
|
140 |
+ |
|
141 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'directory'))
|
|
142 |
+def test_stage_directory_symlink(cli, tmpdir, datafiles):
|
|
143 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
144 |
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
|
|
145 |
+ |
|
146 |
+ symlink = os.path.join(project, 'files', 'symlink-to-subdir')
|
|
147 |
+ os.symlink('subdir', symlink)
|
|
148 |
+ |
|
149 |
+ # Build, checkout
|
|
150 |
+ result = cli.run(project=project, args=['build', 'target.bst'])
|
|
151 |
+ result.assert_success()
|
|
152 |
+ result = cli.run(project=project, args=['artifact', 'checkout', 'target.bst', '--directory', checkoutdir])
|
|
153 |
+ result.assert_success()
|
|
154 |
+ |
|
155 |
+ # Check that the checkout contains the expected directory and directory symlink
|
|
156 |
+ assert(os.path.exists(os.path.join(checkoutdir, 'subdir', 'anotherfile.txt')))
|
|
157 |
+ assert(os.path.exists(os.path.join(checkoutdir, 'symlink-to-subdir', 'anotherfile.txt')))
|
|
158 |
+ assert(os.path.islink(os.path.join(checkoutdir, 'symlink-to-subdir')))
|