[Notes] [Git][BuildStream/buildstream][element-path_not_validated] 16 commits: Fix cache corruption by scripts when layout and integration commands are used



Title: GitLab

Phillip Smyth pushed to branch element-path_not_validated at BuildStream / buildstream

Commits:

26 changed files:

Changes:

  • CONTRIBUTING.rst
    ... ... @@ -97,7 +97,13 @@ a new merge request. You can also `create a merge request for an existing branch
    97 97
     You may open merge requests for the branches you create before you are ready
    
    98 98
     to have them reviewed and considered for inclusion if you like. Until your merge
    
    99 99
     request is ready for review, the merge request title must be prefixed with the
    
    100
    -``WIP:`` identifier.
    
    100
    +``WIP:`` identifier. GitLab `treats this specially
    
    101
    +<https://docs.gitlab.com/ee/user/project/merge_requests/work_in_progress_merge_requests.html>`_,
    
    102
    +which helps reviewers.
    
    103
    +
    
    104
    +Consider marking a merge request as WIP again if you are taking a while to
    
    105
    +address a review point. This signals that the next action is on you, and it
    
    106
    +won't appear in a reviewer's search for non-WIP merge requests to review.
    
    101 107
     
    
    102 108
     
    
    103 109
     Organized commits
    
    ... ... @@ -122,6 +128,12 @@ If a commit in your branch modifies behavior such that a test must also
    122 128
     be changed to match the new behavior, then the tests should be updated
    
    123 129
     with the same commit, so that every commit passes its own tests.
    
    124 130
     
    
    131
    +These principles apply whenever a branch is non-WIP. So for example, don't push
    
    132
    +'fixup!' commits when addressing review comments, instead amend the commits
    
    133
    +directly before pushing. GitLab has `good support
    
    134
    +<https://docs.gitlab.com/ee/user/project/merge_requests/versions.html>`_ for
    
    135
    +diffing between pushes, so 'fixup!' commits are not necessary for reviewers.
    
    136
    +
    
    125 137
     
    
    126 138
     Commit messages
    
    127 139
     ~~~~~~~~~~~~~~~
    
    ... ... @@ -144,6 +156,16 @@ number must be referenced in the commit message.
    144 156
     
    
    145 157
       Fixes #123
    
    146 158
     
    
    159
    +Note that the 'why' of a change is as important as the 'what'.
    
    160
    +
    
    161
    +When reviewing this, folks can suggest better alternatives when they know the
    
    162
    +'why'. Perhaps there are other ways to avoid an error when things are not
    
    163
    +frobnicated.
    
    164
    +
    
    165
    +When folks modify this code, there may be uncertainty around whether the foos
    
    166
    +should always be frobnicated. The comments, the commit message, and issue #123
    
    167
    +should shed some light on that.
    
    168
    +
    
    147 169
     In the case that you have a commit which necessarily modifies multiple
    
    148 170
     components, then the summary line should still mention generally what
    
    149 171
     changed (if possible), followed by a colon and a brief summary.
    

  • buildstream/_platform/linux.py
    ... ... @@ -18,9 +18,9 @@
    18 18
     #        Tristan Maat <tristan maat codethink co uk>
    
    19 19
     
    
    20 20
     import os
    
    21
    +import shutil
    
    21 22
     import subprocess
    
    22 23
     
    
    23
    -from .. import _site
    
    24 24
     from .. import utils
    
    25 25
     from ..sandbox import SandboxDummy
    
    26 26
     
    
    ... ... @@ -37,12 +37,19 @@ class Linux(Platform):
    37 37
             self._gid = os.getegid()
    
    38 38
     
    
    39 39
             self._have_fuse = os.path.exists("/dev/fuse")
    
    40
    -        self._bwrap_exists = _site.check_bwrap_version(0, 0, 0)
    
    41
    -        self._have_good_bwrap = _site.check_bwrap_version(0, 1, 2)
    
    42 40
     
    
    43
    -        self._local_sandbox_available = self._have_fuse and self._have_good_bwrap
    
    41
    +        bwrap_version = self._get_bwrap_version()
    
    44 42
     
    
    45
    -        self._die_with_parent_available = _site.check_bwrap_version(0, 1, 8)
    
    43
    +        if bwrap_version is None:
    
    44
    +            self._bwrap_exists = False
    
    45
    +            self._have_good_bwrap = False
    
    46
    +            self._die_with_parent_available = False
    
    47
    +        else:
    
    48
    +            self._bwrap_exists = True
    
    49
    +            self._have_good_bwrap = (0, 1, 2) <= bwrap_version
    
    50
    +            self._die_with_parent_available = (0, 1, 8) <= bwrap_version
    
    51
    +
    
    52
    +        self._local_sandbox_available = self._have_fuse and self._have_good_bwrap
    
    46 53
     
    
    47 54
             if self._local_sandbox_available:
    
    48 55
                 self._user_ns_available = self._check_user_ns_available()
    
    ... ... @@ -112,3 +119,21 @@ class Linux(Platform):
    112 119
                 output = ''
    
    113 120
     
    
    114 121
             return output == 'root'
    
    122
    +
    
    123
    +    def _get_bwrap_version(self):
    
    124
    +        # Get the current bwrap version
    
    125
    +        #
    
    126
    +        # returns None if no bwrap was found
    
    127
    +        # otherwise returns a tuple of 3 int: major, minor, patch
    
    128
    +        bwrap_path = shutil.which('bwrap')
    
    129
    +
    
    130
    +        if not bwrap_path:
    
    131
    +            return None
    
    132
    +
    
    133
    +        cmd = [bwrap_path, "--version"]
    
    134
    +        try:
    
    135
    +            version = str(subprocess.check_output(cmd).split()[1], "utf-8")
    
    136
    +        except subprocess.CalledProcessError:
    
    137
    +            return None
    
    138
    +
    
    139
    +        return tuple(int(x) for x in version.split("."))

  • buildstream/_project.py
    ... ... @@ -219,6 +219,19 @@ class Project():
    219 219
     
    
    220 220
             return self._cache_key
    
    221 221
     
    
    222
    +    def validate_nodes(self, node):
    
    223
    +        _yaml.node_validate(node, [
    
    224
    +            'format-version',
    
    225
    +            'element-path', 'variables',
    
    226
    +            'environment', 'environment-nocache',
    
    227
    +            'split-rules', 'elements', 'plugins',
    
    228
    +            'aliases', 'name',
    
    229
    +            'artifacts', 'options',
    
    230
    +            'fail-on-overlap', 'shell', 'fatal-warnings',
    
    231
    +            '(@)', 'sources',
    
    232
    +            'ref-storage', 'sandbox', 'mirrors', 'remote-execution'
    
    233
    +        ])
    
    234
    +
    
    222 235
         # create_element()
    
    223 236
         #
    
    224 237
         # Instantiate and return an element
    
    ... ... @@ -402,6 +415,8 @@ class Project():
    402 415
                     "Project requested format version {}, but BuildStream {}.{} only supports up until format version {}"
    
    403 416
                     .format(format_version, major, minor, BST_FORMAT_VERSION))
    
    404 417
     
    
    418
    +        self.validate_nodes(pre_config_node)
    
    419
    +
    
    405 420
             # FIXME:
    
    406 421
             #
    
    407 422
             #   Performing this check manually in the absense
    
    ... ... @@ -467,16 +482,7 @@ class Project():
    467 482
     
    
    468 483
             self._load_pass(config, self.config)
    
    469 484
     
    
    470
    -        _yaml.node_validate(config, [
    
    471
    -            'format-version',
    
    472
    -            'element-path', 'variables',
    
    473
    -            'environment', 'environment-nocache',
    
    474
    -            'split-rules', 'elements', 'plugins',
    
    475
    -            'aliases', 'name',
    
    476
    -            'artifacts', 'options',
    
    477
    -            'fail-on-overlap', 'shell', 'fatal-warnings',
    
    478
    -            'ref-storage', 'sandbox', 'mirrors', 'remote-execution'
    
    479
    -        ])
    
    485
    +        self.validate_nodes(config)
    
    480 486
     
    
    481 487
             #
    
    482 488
             # Now all YAML composition is done, from here on we just load
    

  • buildstream/_site.py
    ... ... @@ -18,8 +18,6 @@
    18 18
     #        Tristan Van Berkom <tristan vanberkom codethink co uk>
    
    19 19
     
    
    20 20
     import os
    
    21
    -import shutil
    
    22
    -import subprocess
    
    23 21
     
    
    24 22
     #
    
    25 23
     # Private module declaring some info about where the buildstream
    
    ... ... @@ -46,44 +44,3 @@ build_all_template = os.path.join(root, 'data', 'build-all.sh.in')
    46 44
     
    
    47 45
     # Module building script template
    
    48 46
     build_module_template = os.path.join(root, 'data', 'build-module.sh.in')
    49
    -
    
    50
    -# Cached bwrap version
    
    51
    -_bwrap_major = None
    
    52
    -_bwrap_minor = None
    
    53
    -_bwrap_patch = None
    
    54
    -
    
    55
    -
    
    56
    -# check_bwrap_version()
    
    57
    -#
    
    58
    -# Checks the version of installed bwrap against the requested version
    
    59
    -#
    
    60
    -# Args:
    
    61
    -#    major (int): The required major version
    
    62
    -#    minor (int): The required minor version
    
    63
    -#    patch (int): The required patch level
    
    64
    -#
    
    65
    -# Returns:
    
    66
    -#    (bool): Whether installed bwrap meets the requirements
    
    67
    -#
    
    68
    -def check_bwrap_version(major, minor, patch):
    
    69
    -    # pylint: disable=global-statement
    
    70
    -
    
    71
    -    global _bwrap_major
    
    72
    -    global _bwrap_minor
    
    73
    -    global _bwrap_patch
    
    74
    -
    
    75
    -    # Parse bwrap version and save into cache, if not already cached
    
    76
    -    if _bwrap_major is None:
    
    77
    -        bwrap_path = shutil.which('bwrap')
    
    78
    -        if not bwrap_path:
    
    79
    -            return False
    
    80
    -        cmd = [bwrap_path, "--version"]
    
    81
    -        try:
    
    82
    -            version = str(subprocess.check_output(cmd).split()[1], "utf-8")
    
    83
    -        except subprocess.CalledProcessError:
    
    84
    -            # Failure trying to run bubblewrap
    
    85
    -            return False
    
    86
    -        _bwrap_major, _bwrap_minor, _bwrap_patch = map(int, version.split("."))
    
    87
    -
    
    88
    -    # Check whether the installed version meets the requirements
    
    89
    -    return (_bwrap_major, _bwrap_minor, _bwrap_patch) >= (major, minor, patch)

  • buildstream/data/projectconfig.yaml
    ... ... @@ -62,6 +62,11 @@ variables:
    62 62
               -o -name '*.cmxs' -o -name '*.node' ')' \
    
    63 63
           -exec sh -ec \
    
    64 64
           'read -n4 hdr <"$1" # check for elf header
    
    65
    +       case "$1" in
    
    66
    +         %{install-root}%{debugdir}/*)
    
    67
    +           exit 0
    
    68
    +           ;;
    
    69
    +       esac
    
    65 70
            if [ "$hdr" != "$(printf \\x7fELF)" ]; then
    
    66 71
                exit 0
    
    67 72
            fi
    

  • buildstream/sandbox/_sandboxdummy.py
    ... ... @@ -42,4 +42,5 @@ class SandboxDummy(Sandbox):
    42 42
                                    "'{}'".format(command[0]),
    
    43 43
                                    reason='missing-command')
    
    44 44
     
    
    45
    -        raise SandboxError("This platform does not support local builds: {}".format(self._reason))
    45
    +        raise SandboxError("This platform does not support local builds: {}".format(self._reason),
    
    46
    +                           reason="unavailable-local-sandbox")

  • buildstream/scriptelement.py
    ... ... @@ -201,16 +201,20 @@ class ScriptElement(Element):
    201 201
             # Setup environment
    
    202 202
             sandbox.set_environment(self.get_environment())
    
    203 203
     
    
    204
    +        # Tell the sandbox to mount the install root
    
    205
    +        directories = {self.__install_root: False}
    
    206
    +
    
    204 207
             # Mark the artifact directories in the layout
    
    205 208
             for item in self.__layout:
    
    206
    -            if item['destination'] != '/':
    
    207
    -                if item['element']:
    
    208
    -                    sandbox.mark_directory(item['destination'], artifact=True)
    
    209
    -                else:
    
    210
    -                    sandbox.mark_directory(item['destination'])
    
    211
    -
    
    212
    -        # Tell the sandbox to mount the install root
    
    213
    -        sandbox.mark_directory(self.__install_root)
    
    209
    +            destination = item['destination']
    
    210
    +            was_artifact = directories.get(destination, False)
    
    211
    +            directories[destination] = item['element'] or was_artifact
    
    212
    +
    
    213
    +        for directory, artifact in directories.items():
    
    214
    +            # Root does not need to be marked as it is always mounted
    
    215
    +            # with artifact (unless explicitly marked non-artifact)
    
    216
    +            if directory != '/':
    
    217
    +                sandbox.mark_directory(directory, artifact=artifact)
    
    214 218
     
    
    215 219
         def stage(self, sandbox):
    
    216 220
     
    

  • conftest.py
    ... ... @@ -23,6 +23,8 @@ import shutil
    23 23
     
    
    24 24
     import pytest
    
    25 25
     
    
    26
    +from buildstream._platform.platform import Platform
    
    27
    +
    
    26 28
     
    
    27 29
     def pytest_addoption(parser):
    
    28 30
         parser.addoption('--integration', action='store_true', default=False,
    
    ... ... @@ -52,3 +54,8 @@ def integration_cache(request):
    52 54
             shutil.rmtree(os.path.join(cache_dir, 'artifacts'))
    
    53 55
         except FileNotFoundError:
    
    54 56
             pass
    
    57
    +
    
    58
    +
    
    59
    +@pytest.fixture(autouse=True)
    
    60
    +def clean_platform_cache():
    
    61
    +    Platform._instance = None

  • tests/cachekey/project/elements/build1.expected
    1
    -dd5e29baefb84f68eb4abac3a1befc332077ec4c97bb2572e57f3ca98ba46707
    \ No newline at end of file
    1
    +ce0ddf7126d45d14f5ec1a525337c39ec8ddbbe4b0ec2ef51bae777619ed39bb
    \ No newline at end of file

  • tests/cachekey/project/elements/build2.expected
    1
    -99d80454cce44645597c885800edf0bf254d1c3606d869f2ccdd5043ec7685cb
    \ No newline at end of file
    1
    +5e2a48dbeae43f6bab84071dbd02345a3aa32a473c189645ab26f3d5d6cfe547
    \ No newline at end of file

  • tests/cachekey/project/target.expected
    1
    -29a1252ec30dd6ae73c772381f0eb417e3874c75710d08be819f5715dcaa942b
    \ No newline at end of file
    1
    +125d9e7dcf4f49e5f80d85b7f144b43ed43186064afc2e596e57f26cce679cf5
    \ No newline at end of file

  • tests/frontend/invalid_element_path/project.conf
    1
    +# Project config for frontend build test
    
    2
    +name: test
    
    3
    +
    
    4
    +elephant-path: elements

  • tests/frontend/show.py
    ... ... @@ -36,6 +36,19 @@ def test_show(cli, datafiles, target, format, expected):
    36 36
                                  .format(expected, result.output))
    
    37 37
     
    
    38 38
     
    
    39
    +@pytest.mark.datafiles(os.path.join(
    
    40
    +    os.path.dirname(os.path.realpath(__file__)),
    
    41
    +    "invalid_element_path",
    
    42
    +))
    
    43
    +def test_show_invalid_element_path(cli, datafiles):
    
    44
    +    project = os.path.join(datafiles.dirname, datafiles.basename)
    
    45
    +    result = cli.run(project=project, silent=True, args=[
    
    46
    +        'show',
    
    47
    +        "foo.bst"])
    
    48
    +
    
    49
    +    result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA)
    
    50
    +
    
    51
    +
    
    39 52
     @pytest.mark.datafiles(DATA_DIR)
    
    40 53
     @pytest.mark.parametrize("target,except_,expected", [
    
    41 54
         ('target.bst', 'import-bin.bst', ['import-dev.bst', 'compose-all.bst', 'target.bst']),
    

  • tests/integration/project/elements/script/corruption-2.bst
    1
    +kind: script
    
    2
    +
    
    3
    +depends:
    
    4
    +- filename: base.bst
    
    5
    +  type: build
    
    6
    +- filename: script/corruption-image.bst
    
    7
    +  type: build
    
    8
    +
    
    9
    +config:
    
    10
    +  commands:
    
    11
    +  - echo smashed >>/canary

  • tests/integration/project/elements/script/corruption-image.bst
    1
    +kind: import
    
    2
    +sources:
    
    3
    +- kind: local
    
    4
    +  path: files/canary

  • tests/integration/project/elements/script/corruption-integration.bst
    1
    +kind: stack
    
    2
    +
    
    3
    +public:
    
    4
    +  bst:
    
    5
    +    integration-commands:
    
    6
    +      - echo smashed >>/canary
    
    7
    +

  • tests/integration/project/elements/script/corruption.bst
    1
    +kind: script
    
    2
    +
    
    3
    +depends:
    
    4
    +- filename: base.bst
    
    5
    +  type: build
    
    6
    +- filename: script/corruption-image.bst
    
    7
    +  type: build
    
    8
    +- filename: script/corruption-integration.bst
    
    9
    +  type: build
    
    10
    +
    
    11
    +variables:
    
    12
    +  install-root: "/"
    
    13
    +
    
    14
    +config:
    
    15
    +  layout:
    
    16
    +  - element: base.bst
    
    17
    +    destination: "/"
    
    18
    +  - element: script/corruption-image.bst
    
    19
    +    destination: "/"
    
    20
    +  - element: script/corruption-integration.bst
    
    21
    +    destination: "/"

  • tests/integration/project/elements/script/marked-tmpdir.bst
    1
    +kind: compose
    
    2
    +
    
    3
    +depends:
    
    4
    +- filename: base.bst
    
    5
    +  type: build
    
    6
    +
    
    7
    +public:
    
    8
    +  bst:
    
    9
    +    split-rules:
    
    10
    +      remove:
    
    11
    +        - "/tmp/**"
    
    12
    +        - "/tmp"

  • tests/integration/project/elements/script/no-tmpdir.bst
    1
    +kind: filter
    
    2
    +
    
    3
    +depends:
    
    4
    +- filename: script/marked-tmpdir.bst
    
    5
    +  type: build
    
    6
    +
    
    7
    +config:
    
    8
    +  exclude:
    
    9
    +  - remove
    
    10
    +  include-orphans: True
    
    11
    +
    
    12
    +

  • tests/integration/project/elements/script/tmpdir.bst
    1
    +kind: script
    
    2
    +
    
    3
    +depends:
    
    4
    +- filename: script/no-tmpdir.bst
    
    5
    +  type: build
    
    6
    +
    
    7
    +config:
    
    8
    +  commands:
    
    9
    +  - |
    
    10
    +    mkdir -p /tmp/blah

  • tests/integration/project/files/canary
    1
    +alive

  • tests/integration/script.py
    ... ... @@ -155,3 +155,70 @@ def test_script_layout(cli, tmpdir, datafiles):
    155 155
             text = f.read()
    
    156 156
     
    
    157 157
         assert text == "Hi\n"
    
    158
    +
    
    159
    +
    
    160
    +@pytest.mark.datafiles(DATA_DIR)
    
    161
    +def test_regression_cache_corruption(cli, tmpdir, datafiles):
    
    162
    +    project = str(datafiles)
    
    163
    +    checkout_original = os.path.join(cli.directory, 'checkout-original')
    
    164
    +    checkout_after = os.path.join(cli.directory, 'checkout-after')
    
    165
    +    element_name = 'script/corruption.bst'
    
    166
    +    canary_element_name = 'script/corruption-image.bst'
    
    167
    +
    
    168
    +    res = cli.run(project=project, args=['build', canary_element_name])
    
    169
    +    assert res.exit_code == 0
    
    170
    +
    
    171
    +    res = cli.run(project=project, args=['checkout', canary_element_name,
    
    172
    +                                         checkout_original])
    
    173
    +    assert res.exit_code == 0
    
    174
    +
    
    175
    +    with open(os.path.join(checkout_original, 'canary')) as f:
    
    176
    +        assert f.read() == 'alive\n'
    
    177
    +
    
    178
    +    res = cli.run(project=project, args=['build', element_name])
    
    179
    +    assert res.exit_code == 0
    
    180
    +
    
    181
    +    res = cli.run(project=project, args=['checkout', canary_element_name,
    
    182
    +                                         checkout_after])
    
    183
    +    assert res.exit_code == 0
    
    184
    +
    
    185
    +    with open(os.path.join(checkout_after, 'canary')) as f:
    
    186
    +        assert f.read() == 'alive\n'
    
    187
    +
    
    188
    +
    
    189
    +@pytest.mark.datafiles(DATA_DIR)
    
    190
    +def test_regression_tmpdir(cli, tmpdir, datafiles):
    
    191
    +    project = str(datafiles)
    
    192
    +    element_name = 'script/tmpdir.bst'
    
    193
    +
    
    194
    +    res = cli.run(project=project, args=['build', element_name])
    
    195
    +    assert res.exit_code == 0
    
    196
    +
    
    197
    +
    
    198
    +@pytest.mark.datafiles(DATA_DIR)
    
    199
    +def test_regression_cache_corruption_2(cli, tmpdir, datafiles):
    
    200
    +    project = str(datafiles)
    
    201
    +    checkout_original = os.path.join(cli.directory, 'checkout-original')
    
    202
    +    checkout_after = os.path.join(cli.directory, 'checkout-after')
    
    203
    +    element_name = 'script/corruption-2.bst'
    
    204
    +    canary_element_name = 'script/corruption-image.bst'
    
    205
    +
    
    206
    +    res = cli.run(project=project, args=['build', canary_element_name])
    
    207
    +    assert res.exit_code == 0
    
    208
    +
    
    209
    +    res = cli.run(project=project, args=['checkout', canary_element_name,
    
    210
    +                                         checkout_original])
    
    211
    +    assert res.exit_code == 0
    
    212
    +
    
    213
    +    with open(os.path.join(checkout_original, 'canary')) as f:
    
    214
    +        assert f.read() == 'alive\n'
    
    215
    +
    
    216
    +    res = cli.run(project=project, args=['build', element_name])
    
    217
    +    assert res.exit_code == 0
    
    218
    +
    
    219
    +    res = cli.run(project=project, args=['checkout', canary_element_name,
    
    220
    +                                         checkout_after])
    
    221
    +    assert res.exit_code == 0
    
    222
    +
    
    223
    +    with open(os.path.join(checkout_after, 'canary')) as f:
    
    224
    +        assert f.read() == 'alive\n'

  • tests/sandboxes/missing-dependencies/elements/base.bst
    1
    +kind: import
    
    2
    +sources:
    
    3
    +- kind: local
    
    4
    +  path: files/base/

  • tests/sandboxes/missing-dependencies/files/base/bin/sh
    1
    +# This is the original bash

  • tests/sandboxes/missing-dependencies/project.conf
    1
    +# Project config for missing dependencies test
    
    2
    +name: test
    
    3
    +
    
    4
    +element-path: elements

  • tests/sandboxes/missing_dependencies.py
    1
    +import os
    
    2
    +import pytest
    
    3
    +from tests.testutils import cli
    
    4
    +from tests.testutils.site import IS_LINUX
    
    5
    +
    
    6
    +from buildstream import _yaml
    
    7
    +from buildstream._exceptions import ErrorDomain
    
    8
    +
    
    9
    +
    
    10
    +# Project directory
    
    11
    +DATA_DIR = os.path.join(
    
    12
    +    os.path.dirname(os.path.realpath(__file__)),
    
    13
    +    "missing-dependencies",
    
    14
    +)
    
    15
    +
    
    16
    +
    
    17
    +@pytest.mark.skipif(not IS_LINUX, reason='Only available on Linux')
    
    18
    +@pytest.mark.datafiles(DATA_DIR)
    
    19
    +def test_missing_brwap_has_nice_error_message(cli, datafiles):
    
    20
    +    project = os.path.join(datafiles.dirname, datafiles.basename)
    
    21
    +    element_path = os.path.join(project, 'elements', 'element.bst')
    
    22
    +
    
    23
    +    # Write out our test target
    
    24
    +    element = {
    
    25
    +        'kind': 'script',
    
    26
    +        'depends': [
    
    27
    +            {
    
    28
    +                'filename': 'base.bst',
    
    29
    +                'type': 'build',
    
    30
    +            },
    
    31
    +        ],
    
    32
    +        'config': {
    
    33
    +            'commands': [
    
    34
    +                'false',
    
    35
    +            ],
    
    36
    +        },
    
    37
    +    }
    
    38
    +    _yaml.dump(element, element_path)
    
    39
    +
    
    40
    +    # Build without access to host tools, this should fail with a nice error
    
    41
    +    result = cli.run(
    
    42
    +        project=project, args=['build', 'element.bst'], env={'PATH': ''})
    
    43
    +    result.assert_task_error(ErrorDomain.SANDBOX, 'unavailable-local-sandbox')
    
    44
    +    assert "not found" in result.stderr
    
    45
    +
    
    46
    +
    
    47
    +@pytest.mark.skipif(not IS_LINUX, reason='Only available on Linux')
    
    48
    +@pytest.mark.datafiles(DATA_DIR)
    
    49
    +def test_old_brwap_has_nice_error_message(cli, datafiles, tmp_path):
    
    50
    +    bwrap = tmp_path.joinpath('bin/bwrap')
    
    51
    +    bwrap.parent.mkdir()
    
    52
    +    with bwrap.open('w') as fp:
    
    53
    +        fp.write('''
    
    54
    +            #!/bin/sh
    
    55
    +            echo bubblewrap 0.0.1
    
    56
    +        '''.strip())
    
    57
    +
    
    58
    +    bwrap.chmod(0o755)
    
    59
    +
    
    60
    +    project = os.path.join(datafiles.dirname, datafiles.basename)
    
    61
    +    element_path = os.path.join(project, 'elements', 'element3.bst')
    
    62
    +
    
    63
    +    # Write out our test target
    
    64
    +    element = {
    
    65
    +        'kind': 'script',
    
    66
    +        'depends': [
    
    67
    +            {
    
    68
    +                'filename': 'base.bst',
    
    69
    +                'type': 'build',
    
    70
    +            },
    
    71
    +        ],
    
    72
    +        'config': {
    
    73
    +            'commands': [
    
    74
    +                'false',
    
    75
    +            ],
    
    76
    +        },
    
    77
    +    }
    
    78
    +    _yaml.dump(element, element_path)
    
    79
    +
    
    80
    +    # Build without access to host tools, this should fail with a nice error
    
    81
    +    result = cli.run(
    
    82
    +        project=project,
    
    83
    +        args=['--debug', '--verbose', 'build', 'element3.bst'],
    
    84
    +        env={'PATH': str(tmp_path.joinpath('bin'))})
    
    85
    +    result.assert_task_error(ErrorDomain.SANDBOX, 'unavailable-local-sandbox')
    
    86
    +    assert "too old" in result.stderr



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]