Valentin David pushed to branch valentindavid/link_files_sort_resolved at BuildStream / buildstream
Commits:
-
52c58c28
by Valentin David at 2019-01-04T15:06:32Z
-
c99058de
by Valentin David at 2019-01-04T15:06:32Z
12 changed files:
- buildstream/utils.py
- + tests/integration/compose-symlink-order.py
- tests/integration/compose-symlinks.py
- + tests/integration/project/elements/compose-symlink-order/a.bst
- + tests/integration/project/elements/compose-symlink-order/b.bst
- + tests/integration/project/elements/compose-symlink-order/compose.bst
- + tests/integration/project/elements/compose-symlinks/a-foo-symlink.bst
- + tests/integration/project/elements/compose-symlinks/compose-absolute-symlink.bst
- + tests/integration/project/elements/compose-symlinks/foo-dir.bst
- + tests/integration/project/elements/compose-symlinks/integration-move-dir.bst
- + tests/integration/project/files/compose-symlink-order/a/b/.keep
- + tests/integration/project/files/compose-symlink-order/b/a/c/d
Changes:
| ... | ... | @@ -787,6 +787,48 @@ def _ensure_real_directory(root, destpath): |
| 787 | 787 |
return destpath_resolved
|
| 788 | 788 |
|
| 789 | 789 |
|
| 790 |
+@functools.lru_cache(maxsize=1)
|
|
| 791 |
+def _symloop_max():
|
|
| 792 |
+ if hasattr(os, 'sysconf'):
|
|
| 793 |
+ try:
|
|
| 794 |
+ ret = os.sysconf('_SC_SYMLOOP_MAX')
|
|
| 795 |
+ if ret != -1:
|
|
| 796 |
+ return ret
|
|
| 797 |
+ except ValueError:
|
|
| 798 |
+ pass
|
|
| 799 |
+ return 8
|
|
| 800 |
+ |
|
| 801 |
+ |
|
| 802 |
+@functools.lru_cache(maxsize=64)
|
|
| 803 |
+def _sysroot_realpath(path, sysroot):
|
|
| 804 |
+ assert not os.path.isabs(path)
|
|
| 805 |
+ assert os.path.isabs(sysroot)
|
|
| 806 |
+ |
|
| 807 |
+ loop_count = _symloop_max()
|
|
| 808 |
+ while True:
|
|
| 809 |
+ full_path = os.path.join(sysroot, path)
|
|
| 810 |
+ st = os.lstat(full_path)
|
|
| 811 |
+ mode = st.st_mode
|
|
| 812 |
+ if not stat.S_ISLNK(mode):
|
|
| 813 |
+ break
|
|
| 814 |
+ loop_count = loop_count - 1
|
|
| 815 |
+ if loop_count < 0:
|
|
| 816 |
+ raise UtilError("Symlink loop detected: {}".format(os.path.join(sysroot, path)))
|
|
| 817 |
+ link_path = os.readlink(full_path)
|
|
| 818 |
+ if not os.path.isabs(link_path):
|
|
| 819 |
+ link_path = os.path.join('/', os.path.dirname(path), link_path)
|
|
| 820 |
+ path = os.path.relpath(os.path.normpath(link_path), '/')
|
|
| 821 |
+ |
|
| 822 |
+ parent = os.path.dirname(path)
|
|
| 823 |
+ if parent != '':
|
|
| 824 |
+ parent = _sysroot_realpath(parent, sysroot)
|
|
| 825 |
+ full_parent = os.path.join(sysroot, parent)
|
|
| 826 |
+ if not os.path.isdir(full_parent):
|
|
| 827 |
+ raise UtilError("Path is not a directory: {}".format(full_parent))
|
|
| 828 |
+ |
|
| 829 |
+ return os.path.join(parent, os.path.basename(path))
|
|
| 830 |
+ |
|
| 831 |
+ |
|
| 790 | 832 |
# _process_list()
|
| 791 | 833 |
#
|
| 792 | 834 |
# Internal helper for copying/moving/linking file lists
|
| ... | ... | @@ -816,7 +858,16 @@ def _process_list(srcdir, destdir, filelist, actionfunc, result, |
| 816 | 858 |
# symbolic links which lead to directories before processing files inside
|
| 817 | 859 |
# those directories.
|
| 818 | 860 |
if not presorted:
|
| 819 |
- filelist = sorted(filelist)
|
|
| 861 |
+ resolved = []
|
|
| 862 |
+ _sysroot_realpath.cache_clear()
|
|
| 863 |
+ for f in filelist:
|
|
| 864 |
+ dirname = os.path.dirname(f)
|
|
| 865 |
+ dirname = _sysroot_realpath(dirname, srcdir)
|
|
| 866 |
+ if dirname == '.':
|
|
| 867 |
+ resolved.append(os.path.basename(f))
|
|
| 868 |
+ else:
|
|
| 869 |
+ resolved.append(os.path.join(dirname, os.path.basename(f)))
|
|
| 870 |
+ filelist = sorted(resolved)
|
|
| 820 | 871 |
|
| 821 | 872 |
# Now walk the list
|
| 822 | 873 |
for path in filelist:
|
| 1 |
+import os
|
|
| 2 |
+import pytest
|
|
| 3 |
+ |
|
| 4 |
+from buildstream import _yaml
|
|
| 5 |
+ |
|
| 6 |
+from tests.testutils import cli_integration as cli
|
|
| 7 |
+from tests.testutils.site import IS_LINUX, HAVE_BWRAP
|
|
| 8 |
+ |
|
| 9 |
+ |
|
| 10 |
+pytestmark = pytest.mark.integration
|
|
| 11 |
+ |
|
| 12 |
+ |
|
| 13 |
+DATA_DIR = os.path.join(
|
|
| 14 |
+ os.path.dirname(os.path.realpath(__file__)),
|
|
| 15 |
+ "project"
|
|
| 16 |
+)
|
|
| 17 |
+ |
|
| 18 |
+ |
|
| 19 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
| 20 |
+@pytest.mark.skipif(not IS_LINUX or not HAVE_BWRAP, reason='Only available on linux with bubblewrap')
|
|
| 21 |
+def test_compose_symlinks_bad_order(cli, tmpdir, datafiles):
|
|
| 22 |
+ project = str(datafiles)
|
|
| 23 |
+ checkout = os.path.join(cli.directory, 'checkout')
|
|
| 24 |
+ element_path = os.path.join(project, 'elements')
|
|
| 25 |
+ |
|
| 26 |
+ a_files = os.path.join(project, 'files', 'compose-symlink-order', 'a')
|
|
| 27 |
+ os.symlink('b', os.path.join(a_files, 'a'),
|
|
| 28 |
+ target_is_directory=True)
|
|
| 29 |
+ |
|
| 30 |
+ result = cli.run(project=project,
|
|
| 31 |
+ args=['build', 'compose-symlink-order/compose.bst'])
|
|
| 32 |
+ result.assert_success()
|
|
| 33 |
+ |
|
| 34 |
+ result = cli.run(project=project,
|
|
| 35 |
+ args=['checkout', 'compose-symlink-order/compose.bst',
|
|
| 36 |
+ checkout])
|
|
| 37 |
+ result.assert_success()
|
|
| 38 |
+ |
|
| 39 |
+ assert os.path.exists(os.path.join(checkout, 'a/c/d'))
|
|
| 40 |
+ assert os.path.exists(os.path.join(checkout, 'b/c/d'))
|
|
| 41 |
+ assert os.path.islink(os.path.join(checkout, 'a'))
|
| ... | ... | @@ -41,3 +41,18 @@ def test_compose_symlinks(cli, tmpdir, datafiles): |
| 41 | 41 |
|
| 42 | 42 |
assert set(walk_dir(checkout)) == set(['/sbin', '/usr', '/usr/sbin',
|
| 43 | 43 |
'/usr/sbin/init', '/usr/sbin/dummy'])
|
| 44 |
+ |
|
| 45 |
+ |
|
| 46 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
| 47 |
+def test_compose_absolute_symlinks(cli, tmpdir, datafiles):
|
|
| 48 |
+ project = str(datafiles)
|
|
| 49 |
+ checkout = os.path.join(cli.directory, 'checkout')
|
|
| 50 |
+ element_path = os.path.join(project, 'elements')
|
|
| 51 |
+ |
|
| 52 |
+ result = cli.run(project=project, args=['build', 'compose-symlinks/compose-absolute-symlink.bst'])
|
|
| 53 |
+ result.assert_success()
|
|
| 54 |
+ |
|
| 55 |
+ result = cli.run(project=project, args=['checkout', 'compose-symlinks/compose-absolute-symlink.bst', checkout])
|
|
| 56 |
+ result.assert_success()
|
|
| 57 |
+ |
|
| 58 |
+ assert os.readlink(os.path.join(checkout, 'foo')) == 'test/foo'
|
| 1 |
+kind: import
|
|
| 2 |
+sources:
|
|
| 3 |
+- kind: local
|
|
| 4 |
+ path: files/compose-symlink-order/a
|
| 1 |
+kind: import
|
|
| 2 |
+depends:
|
|
| 3 |
+- filename: compose-symlink-order/a.bst
|
|
| 4 |
+ |
|
| 5 |
+sources:
|
|
| 6 |
+- kind: local
|
|
| 7 |
+ path: files/compose-symlink-order/b
|
| 1 |
+kind: compose
|
|
| 2 |
+depends:
|
|
| 3 |
+- filename: compose-symlink-order/b.bst
|
|
| 4 |
+ type: build
|
|
| 5 |
+ |
|
| 6 |
+config:
|
|
| 7 |
+ exclude:
|
|
| 8 |
+ - devel
|
| 1 |
+kind: script
|
|
| 2 |
+ |
|
| 3 |
+depends:
|
|
| 4 |
+- filename: base.bst
|
|
| 5 |
+ type: build
|
|
| 6 |
+ |
|
| 7 |
+config:
|
|
| 8 |
+ commands:
|
|
| 9 |
+ - |
|
|
| 10 |
+ mkdir -p "%{install-root}/bar"
|
|
| 11 |
+ ln -s "/bar" "%{install-root}/foo"
|
| 1 |
+kind: compose
|
|
| 2 |
+ |
|
| 3 |
+depends:
|
|
| 4 |
+- filename: compose-symlinks/foo-dir.bst
|
|
| 5 |
+ type: build
|
|
| 6 |
+- filename: compose-symlinks/a-foo-symlink.bst
|
|
| 7 |
+ type: build
|
|
| 8 |
+- filename: compose-symlinks/integration-move-dir.bst
|
|
| 9 |
+ type: build
|
|
| 10 |
+ |
|
| 11 |
+config:
|
|
| 12 |
+ include-orphans: true
|
|
| 13 |
+ exclude:
|
|
| 14 |
+ - dummy
|
| 1 |
+kind: script
|
|
| 2 |
+ |
|
| 3 |
+depends:
|
|
| 4 |
+- filename: base.bst
|
|
| 5 |
+ type: build
|
|
| 6 |
+ |
|
| 7 |
+config:
|
|
| 8 |
+ commands:
|
|
| 9 |
+ - |
|
|
| 10 |
+ mkdir -p "%{install-root}/foo"
|
|
| 11 |
+ echo test >"%{install-root}/foo/foo.txt"
|
| 1 |
+kind: stack
|
|
| 2 |
+ |
|
| 3 |
+depends:
|
|
| 4 |
+- filename: base.bst
|
|
| 5 |
+ |
|
| 6 |
+public:
|
|
| 7 |
+ bst:
|
|
| 8 |
+ integration-commands:
|
|
| 9 |
+ - |
|
|
| 10 |
+ mkdir test
|
|
| 11 |
+ mv foo test/
|
|
| 12 |
+ mv bar test/
|
|
| 13 |
+ ln -s /test/foo /foo
|
|
| 14 |
+ ln -s /test/bar /bar
|
| 1 |
+test
|
