Skip to content

Commit a331ed0

Browse files
dnicolodirgommers
authored andcommitted
BUG: fix handling of files installed via install_subdir
Install files in the right location in case of nested directory structures, and implement handling of exclude_directories and exclude_files. The latter requires Meson 1.1.0 or later. Fixes #317.
1 parent 6dc3905 commit a331ed0

File tree

13 files changed

+138
-48
lines changed

13 files changed

+138
-48
lines changed

mesonpy/__init__.py

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,11 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[T
150150
wheel_files: DefaultDict[str, List[Tuple[pathlib.Path, str]]] = collections.defaultdict(list)
151151
packages: Dict[str, str] = {}
152152

153-
for group in sources.values():
153+
for key, group in sources.items():
154154
for src, target in group.items():
155155
destination = pathlib.Path(target['destination'])
156156
anchor = destination.parts[0]
157+
dst = pathlib.Path(*destination.parts[1:])
157158

158159
path = _INSTALLATION_PATH_MAP.get(anchor)
159160
if path is None:
@@ -170,7 +171,28 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[T
170171
f'{this!r} and {that!r}, a "pure: false" argument may be missing in meson.build. '
171172
f'It is recommended to set it in "import(\'python\').find_installation()"')
172173

173-
wheel_files[path].append((pathlib.Path(*destination.parts[1:]), src))
174+
if key == 'install_subdirs':
175+
assert os.path.isdir(src)
176+
exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])}
177+
exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])}
178+
for root, dirnames, filenames in os.walk(src):
179+
for name in dirnames.copy():
180+
dirsrc = os.path.join(root, name)
181+
relpath = os.path.relpath(dirsrc, src)
182+
if relpath in exclude_dirs:
183+
dirnames.remove(name)
184+
# sort to process directories determninistically
185+
dirnames.sort()
186+
for name in sorted(filenames):
187+
filesrc = os.path.join(root, name)
188+
relpath = os.path.relpath(filesrc, src)
189+
if relpath in exclude_files:
190+
continue
191+
filedst = dst / relpath
192+
wheel_files[path].append((filedst, filesrc))
193+
else:
194+
wheel_files[path].append((dst, src))
195+
174196
return wheel_files
175197

176198

@@ -416,7 +438,7 @@ def _is_native(self, file: Union[str, pathlib.Path]) -> bool:
416438
return True
417439
return False
418440

419-
def _install_path( # noqa: C901
441+
def _install_path(
420442
self,
421443
wheel_file: mesonpy._wheelfile.WheelFile,
422444
origin: Path,
@@ -430,51 +452,39 @@ def _install_path( # noqa: C901
430452
"""
431453
location = destination.as_posix()
432454

433-
# fix file
434-
if os.path.isdir(origin):
435-
for root, dirnames, filenames in os.walk(str(origin)):
436-
# Sort the directory names so that `os.walk` will walk them in a
437-
# defined order on the next iteration.
438-
dirnames.sort()
439-
for name in sorted(filenames):
440-
path = os.path.normpath(os.path.join(root, name))
441-
if os.path.isfile(path):
442-
arcname = os.path.join(destination, os.path.relpath(path, origin).replace(os.path.sep, '/'))
443-
wheel_file.write(path, arcname)
444-
else:
445-
if self._has_internal_libs:
446-
if platform.system() == 'Linux' or platform.system() == 'Darwin':
447-
# add .mesonpy.libs to the RPATH of ELF files
448-
if self._is_native(os.fspath(origin)):
449-
# copy ELF to our working directory to avoid Meson having to regenerate the file
450-
new_origin = self._libs_build_dir / pathlib.Path(origin).relative_to(self._build_dir)
451-
os.makedirs(new_origin.parent, exist_ok=True)
452-
shutil.copy2(origin, new_origin)
453-
origin = new_origin
454-
# add our in-wheel libs folder to the RPATH
455-
if platform.system() == 'Linux':
456-
elf = mesonpy._elf.ELF(origin)
457-
libdir_path = \
458-
f'$ORIGIN/{os.path.relpath(f".{self._project.name}.mesonpy.libs", destination.parent)}'
459-
if libdir_path not in elf.rpath:
460-
elf.rpath = [*elf.rpath, libdir_path]
461-
elif platform.system() == 'Darwin':
462-
dylib = mesonpy._dylib.Dylib(origin)
463-
libdir_path = \
464-
f'@loader_path/{os.path.relpath(f".{self._project.name}.mesonpy.libs", destination.parent)}'
465-
if libdir_path not in dylib.rpath:
466-
dylib.rpath = [*dylib.rpath, libdir_path]
467-
else:
468-
# Internal libraries are currently unsupported on this platform
469-
raise NotImplementedError("Bundling libraries in wheel is not supported on platform '{}'"
470-
.format(platform.system()))
471-
472-
try:
473-
wheel_file.write(origin, location)
474-
except FileNotFoundError:
475-
# work around for Meson bug, see https://github.com/mesonbuild/meson/pull/11655
476-
if not os.fspath(origin).endswith('.pdb'):
477-
raise
455+
if self._has_internal_libs:
456+
if platform.system() == 'Linux' or platform.system() == 'Darwin':
457+
# add .mesonpy.libs to the RPATH of ELF files
458+
if self._is_native(os.fspath(origin)):
459+
# copy ELF to our working directory to avoid Meson having to regenerate the file
460+
new_origin = self._libs_build_dir / pathlib.Path(origin).relative_to(self._build_dir)
461+
os.makedirs(new_origin.parent, exist_ok=True)
462+
shutil.copy2(origin, new_origin)
463+
origin = new_origin
464+
# add our in-wheel libs folder to the RPATH
465+
if platform.system() == 'Linux':
466+
elf = mesonpy._elf.ELF(origin)
467+
libdir_path = \
468+
f'$ORIGIN/{os.path.relpath(f".{self._project.name}.mesonpy.libs", destination.parent)}'
469+
if libdir_path not in elf.rpath:
470+
elf.rpath = [*elf.rpath, libdir_path]
471+
elif platform.system() == 'Darwin':
472+
dylib = mesonpy._dylib.Dylib(origin)
473+
libdir_path = \
474+
f'@loader_path/{os.path.relpath(f".{self._project.name}.mesonpy.libs", destination.parent)}'
475+
if libdir_path not in dylib.rpath:
476+
dylib.rpath = [*dylib.rpath, libdir_path]
477+
else:
478+
# Internal libraries are currently unsupported on this platform
479+
raise NotImplementedError("Bundling libraries in wheel is not supported on platform '{}'"
480+
.format(platform.system()))
481+
482+
try:
483+
wheel_file.write(origin, location)
484+
except FileNotFoundError:
485+
# work around for Meson bug, see https://github.com/mesonbuild/meson/pull/11655
486+
if not os.fspath(origin).endswith('.pdb'):
487+
raise
478488

479489
def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None:
480490
# add metadata
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
project('install-subdir', version: '1.0.0')
6+
7+
py = import('python').find_installation()
8+
9+
install_subdir(
10+
'subdir',
11+
exclude_files: 'excluded.py',
12+
exclude_directories: 'excluded',
13+
install_dir: py.get_install_dir(pure: false),
14+
)
15+
16+
install_subdir(
17+
'strip',
18+
strip_directory: true,
19+
exclude_files: 'excluded.py',
20+
install_dir: py.get_install_dir(pure: false) / 'test',
21+
)
22+
23+
install_subdir(
24+
'nested',
25+
exclude_files: 'deep/excluded.py',
26+
install_dir: py.get_install_dir(pure: false),
27+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: 2021 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
[build-system]
6+
build-backend = 'mesonpy'
7+
requires = ['meson-python']
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2023 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT

0 commit comments

Comments
 (0)