[Notes] [Git][BuildStream/buildstream][jmac/tempfile-extraction-bug] 3 commits: element.py: chmod 777 directories if delete fails.



Title: GitLab

Jim MacArthur pushed to branch jmac/tempfile-extraction-bug at BuildStream / buildstream

Commits:

4 changed files:

Changes:

  • buildstream/element.py
    ... ... @@ -1361,8 +1361,12 @@ class Element(Plugin):
    1361 1361
                 if not vdirectory.is_empty():
    
    1362 1362
                     raise ElementError("Staging directory '{}' is not empty".format(vdirectory))
    
    1363 1363
     
    
    1364
    -            with tempfile.TemporaryDirectory() as temp_staging_directory:
    
    1364
    +            # While mkdtemp is advertised as using the TMP environment variable, it
    
    1365
    +            # doesn't, so this explicit extraction is necesasry.
    
    1366
    +            tmp_prefix = os.environ.get("TMP", None)
    
    1367
    +            temp_staging_directory = tempfile.mkdtemp(prefix=tmp_prefix)
    
    1365 1368
     
    
    1369
    +            try:
    
    1366 1370
                     workspace = self._get_workspace()
    
    1367 1371
                     if workspace:
    
    1368 1372
                         # If mount_workspaces is set and we're doing incremental builds,
    
    ... ... @@ -1377,6 +1381,16 @@ class Element(Plugin):
    1377 1381
                             source._stage(temp_staging_directory)
    
    1378 1382
     
    
    1379 1383
                     vdirectory.import_files(temp_staging_directory)
    
    1384
    +
    
    1385
    +            finally:
    
    1386
    +                # Staging may produce directories with less than 'rwx' permissions
    
    1387
    +                # for the owner, which will break tempfile, so we need to use chmod
    
    1388
    +                # occasionally.
    
    1389
    +                def make_dir_writable(fn, path, excinfo):
    
    1390
    +                    os.chmod(os.path.dirname(path), 0o777)
    
    1391
    +                    os.remove(path)
    
    1392
    +                shutil.rmtree(temp_staging_directory, onerror=make_dir_writable)
    
    1393
    +
    
    1380 1394
             # Ensure deterministic mtime of sources at build time
    
    1381 1395
             vdirectory.set_deterministic_mtime()
    
    1382 1396
             # Ensure deterministic owners of sources at build time
    

  • tests/sources/tar.py
    ... ... @@ -3,6 +3,7 @@ import pytest
    3 3
     import tarfile
    
    4 4
     import tempfile
    
    5 5
     import subprocess
    
    6
    +from shutil import copyfile, rmtree
    
    6 7
     
    
    7 8
     from buildstream._exceptions import ErrorDomain
    
    8 9
     from buildstream import _yaml
    
    ... ... @@ -257,3 +258,44 @@ def test_stage_default_basedir_lzip(cli, tmpdir, datafiles, srcdir):
    257 258
         original_contents = list_dir_contents(original_dir)
    
    258 259
         checkout_contents = list_dir_contents(checkoutdir)
    
    259 260
         assert(checkout_contents == original_contents)
    
    261
    +
    
    262
    +
    
    263
    +# Test that a tarball that contains a read only dir works
    
    264
    +@pytest.mark.datafiles(os.path.join(DATA_DIR, 'read-only'))
    
    265
    +def test_read_only_dir(cli, tmpdir, datafiles):
    
    266
    +    try:
    
    267
    +        project = os.path.join(datafiles.dirname, datafiles.basename)
    
    268
    +        generate_project(project, tmpdir)
    
    269
    +
    
    270
    +        # Get the tarball in tests/sources/tar/read-only/content
    
    271
    +        #
    
    272
    +        # NOTE that we need to do this because tarfile.open and tar.add()
    
    273
    +        # are packing the tar up with writeable files and dirs
    
    274
    +        tarball = os.path.join(str(datafiles), 'content', 'a.tar.gz')
    
    275
    +        if not os.path.exists(tarball):
    
    276
    +            raise FileNotFoundError('{} does not exist'.format(tarball))
    
    277
    +        copyfile(tarball, os.path.join(tmpdir, 'a.tar.gz'))
    
    278
    +
    
    279
    +        # Because this test can potentially leave directories behind
    
    280
    +        # which are difficult to remove, ask buildstream to use
    
    281
    +        # our temp directory, so we can clean up.
    
    282
    +        tmpdir_str = str(tmpdir)
    
    283
    +        if not tmpdir_str.endswith(os.path.sep):
    
    284
    +            tmpdir_str += os.path.sep
    
    285
    +        env = {"TMP": tmpdir_str}
    
    286
    +
    
    287
    +        # Track, fetch, build, checkout
    
    288
    +        result = cli.run(project=project, args=['track', 'target.bst'], env=env)
    
    289
    +        result.assert_success()
    
    290
    +        result = cli.run(project=project, args=['fetch', 'target.bst'], env=env)
    
    291
    +        result.assert_success()
    
    292
    +        result = cli.run(project=project, args=['build', 'target.bst'], env=env)
    
    293
    +        result.assert_success()
    
    294
    +
    
    295
    +    finally:
    
    296
    +
    
    297
    +        # Make tmpdir deletable no matter what happens
    
    298
    +        def make_dir_writable(fn, path, excinfo):
    
    299
    +            os.chmod(os.path.dirname(path), 0o777)
    
    300
    +            os.remove(path)
    
    301
    +        rmtree(str(tmpdir), onerror=make_dir_writable)

  • tests/sources/tar/read-only/content/a.tar.gz
    No preview for this file type
  • tests/sources/tar/read-only/target.bst
    1
    +kind: import
    
    2
    +description: The kind of this element is irrelevant.
    
    3
    +sources:
    
    4
    +- kind: tar
    
    5
    +  url: tmpdir:/a.tar.gz
    
    6
    +  ref: foo



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