From 6ba8c4d628a763981703a6949cb789bb98edfff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Fri, 4 Sep 2026 22:45:07 +0200 Subject: [PATCH] minstall: Treat symlinks to directories as directories if follow_symlinks is enabled in do_copydir() Fix the installation of a subdirectory that contains a symlink to a directory, when follow_symlinks is enabled. Currently, the following error is thrown in that case: > IsADirectoryError: [Errno 21] Is a directory: '' --- mesonbuild/minstall.py | 4 ++-- run_format_tests.py | 2 ++ .../bar/dir1/file1 | 0 .../bar/dir2/dir3 | 1 + .../meson.build | 12 ++++++++++++ .../test.json | 6 +++++- 6 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test cases/common/268 install functions and follow symlinks/bar/dir1/file1 create mode 120000 test cases/common/268 install functions and follow symlinks/bar/dir2/dir3 diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 7600ad1c8..fd6977bd8 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -507,13 +507,13 @@ class Installer: exclude_dirs = {os.path.normpath(x) for x in exclude_dirs} else: exclude_files = exclude_dirs = set() - for root, dirs, files in os.walk(src_dir): + for root, dirs, files in os.walk(src_dir, followlinks=bool(follow_symlinks)): assert os.path.isabs(root) for d in dirs[:]: abs_src = os.path.join(root, d) filepart = os.path.relpath(abs_src, start=src_dir) abs_dst = os.path.join(dst_dir, filepart) - if os.path.islink(abs_src): + if not follow_symlinks and os.path.islink(abs_src): files.append(d) continue # Remove these so they aren't visited by os.walk at all. diff --git a/run_format_tests.py b/run_format_tests.py index 30c975882..f3889a4bd 100755 --- a/run_format_tests.py +++ b/run_format_tests.py @@ -72,6 +72,8 @@ def check_symlinks(): if f.is_symlink(): if 'boost symlinks/boost/lib' in str(f): continue + if 'follow symlinks/bar/dir2/dir3' in str(f): + continue raise SystemExit(f'Test data dir contains symlink: {f}.') diff --git a/test cases/common/268 install functions and follow symlinks/bar/dir1/file1 b/test cases/common/268 install functions and follow symlinks/bar/dir1/file1 new file mode 100644 index 000000000..e69de29bb diff --git a/test cases/common/268 install functions and follow symlinks/bar/dir2/dir3 b/test cases/common/268 install functions and follow symlinks/bar/dir2/dir3 new file mode 120000 index 000000000..c9f3ab1ea --- /dev/null +++ b/test cases/common/268 install functions and follow symlinks/bar/dir2/dir3 @@ -0,0 +1 @@ +../dir1 \ No newline at end of file diff --git a/test cases/common/268 install functions and follow symlinks/meson.build b/test cases/common/268 install functions and follow symlinks/meson.build index 9158ea8ee..de276161d 100644 --- a/test cases/common/268 install functions and follow symlinks/meson.build +++ b/test cases/common/268 install functions and follow symlinks/meson.build @@ -40,3 +40,15 @@ install_subdir( strip_directory: true, follow_symlinks: true, ) + +install_subdir( + 'bar', + install_dir: get_option('datadir') / 'subdir', + follow_symlinks: false, +) + +install_subdir( + 'bar', + install_dir: get_option('datadir') / 'subdir_followed', + follow_symlinks: true, +) diff --git a/test cases/common/268 install functions and follow symlinks/test.json b/test cases/common/268 install functions and follow symlinks/test.json index 6a395177d..e4fe3ec39 100644 --- a/test cases/common/268 install functions and follow symlinks/test.json +++ b/test cases/common/268 install functions and follow symlinks/test.json @@ -7,8 +7,12 @@ {"type": "link", "file": "usr/share/subdir/link1"}, {"type": "link", "file": "usr/share/subdir/link2.h"}, {"type": "file", "file": "usr/share/subdir/file1"}, + {"type": "file", "file": "usr/share/subdir/bar/dir1/file1"}, + {"type": "link", "file": "usr/share/subdir/bar/dir2/dir3"}, {"type": "file", "file": "usr/share/subdir_followed/link1"}, {"type": "file", "file": "usr/share/subdir_followed/link2.h"}, - {"type": "file", "file": "usr/share/subdir_followed/file1"} + {"type": "file", "file": "usr/share/subdir_followed/file1"}, + {"type": "file", "file": "usr/share/subdir_followed/bar/dir1/file1"}, + {"type": "file", "file": "usr/share/subdir_followed/bar/dir2/dir3/file1"} ] }