aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/minstall.py
diff options
context:
space:
mode:
authorPablo Correa Gómez <ablocorrea@hotmail.com>2021-11-22 15:46:15 +0100
committerEli Schwartz <eschwartz93@gmail.com>2021-12-01 13:59:54 -0500
commit4f882ff8ec81cbc42b097d3aee8ca4a8013f538b (patch)
tree9cef0e48e71fda1e116023ca8f0791cdfea59b2c /mesonbuild/minstall.py
parentbb5a09de45a99b657b16edef7a9be423735aec79 (diff)
downloadmeson-4f882ff8ec81cbc42b097d3aee8ca4a8013f538b.zip
meson-4f882ff8ec81cbc42b097d3aee8ca4a8013f538b.tar.gz
meson-4f882ff8ec81cbc42b097d3aee8ca4a8013f538b.tar.bz2
add install_symlink function
Allows installing symlinks directly from meson, which can become useful in multiple scenarios. Current main use is to help moving forward #9557
Diffstat (limited to 'mesonbuild/minstall.py')
-rw-r--r--mesonbuild/minstall.py62
1 files changed, 45 insertions, 17 deletions
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index 7979fe6..60d533c 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -26,7 +26,10 @@ import sys
import typing as T
from . import environment
-from .backend.backends import InstallData, InstallDataBase, InstallEmptyDir, TargetInstallData, ExecutableSerialisation
+from .backend.backends import (
+ InstallData, InstallDataBase, InstallEmptyDir, InstallSymlinkData,
+ TargetInstallData, ExecutableSerialisation
+)
from .coredata import major_versions_differ, MesonVersionMismatchException
from .coredata import version as coredata_version
from .mesonlib import Popen_safe, RealPathAction, is_windows
@@ -317,6 +320,7 @@ class Installer:
def __init__(self, options: 'ArgumentType', lf: T.TextIO):
self.did_install_something = False
+ self.printed_symlink_error = False
self.options = options
self.lf = lf
self.preserved_file_count = 0
@@ -394,7 +398,9 @@ class Installer:
return run_exe(*args, **kwargs)
return 0
- def should_install(self, d: T.Union[TargetInstallData, InstallEmptyDir, InstallDataBase, ExecutableSerialisation]) -> bool:
+ def should_install(self, d: T.Union[TargetInstallData, InstallEmptyDir,
+ InstallDataBase, InstallSymlinkData,
+ ExecutableSerialisation]) -> bool:
if d.subproject and (d.subproject in self.skip_subprojects or '*' in self.skip_subprojects):
return False
if self.tags and d.tag not in self.tags:
@@ -452,6 +458,29 @@ class Installer:
append_to_log(self.lf, to_file)
return True
+ def do_symlink(self, target: str, link: str, full_dst_dir: str) -> bool:
+ abs_target = target
+ if not os.path.isabs(target):
+ abs_target = os.path.join(full_dst_dir, target)
+ if not os.path.exists(abs_target):
+ raise RuntimeError(f'Tried to install symlink to missing file {abs_target}')
+ if os.path.exists(link):
+ if not os.path.islink(link):
+ raise RuntimeError(f'Destination {link!r} already exists and is not a symlink')
+ self.remove(link)
+ if not self.printed_symlink_error:
+ self.log(f'Installing symlink pointing to {target} to {link}')
+ try:
+ self.symlink(target, link, target_is_directory=os.path.isdir(abs_target))
+ except (NotImplementedError, OSError):
+ if not self.printed_symlink_error:
+ print("Symlink creation does not work on this platform. "
+ "Skipping all symlinking.")
+ self.printed_symlink_error = True
+ return False
+ append_to_log(self.lf, link)
+ return True
+
def do_copydir(self, data: InstallData, src_dir: str, dst_dir: str,
exclude: T.Optional[T.Tuple[T.Set[str], T.Set[str]]],
install_mode: 'FileMode', dm: DirMaker) -> None:
@@ -558,6 +587,7 @@ class Installer:
self.install_man(d, dm, destdir, fullprefix)
self.install_emptydir(d, dm, destdir, fullprefix)
self.install_data(d, dm, destdir, fullprefix)
+ self.install_symlinks(d, dm, destdir, fullprefix)
self.restore_selinux_contexts(destdir)
self.apply_ldconfig(dm, destdir, libdir)
self.run_install_script(d, destdir, fullprefix)
@@ -596,6 +626,16 @@ class Installer:
self.did_install_something = True
self.set_mode(outfilename, i.install_mode, d.install_umask)
+ def install_symlinks(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
+ for s in d.symlinks:
+ if not self.should_install(s):
+ continue
+ full_dst_dir = get_destdir_path(destdir, fullprefix, s.install_path)
+ full_link_name = get_destdir_path(destdir, fullprefix, s.name)
+ dm.makedirs(full_dst_dir, exist_ok=True)
+ if self.do_symlink(s.target, full_link_name, full_dst_dir):
+ self.did_install_something = True
+
def install_man(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
for m in d.man:
if not self.should_install(m):
@@ -712,21 +752,9 @@ class Installer:
self.do_copydir(d, fname, outname, None, install_mode, dm)
else:
raise RuntimeError(f'Unknown file type for {fname!r}')
- printed_symlink_error = False
- for alias, to in aliases.items():
- try:
- symlinkfilename = os.path.join(outdir, alias)
- try:
- self.remove(symlinkfilename)
- except FileNotFoundError:
- pass
- self.symlink(to, symlinkfilename)
- append_to_log(self.lf, symlinkfilename)
- except (NotImplementedError, OSError):
- if not printed_symlink_error:
- print("Symlink creation does not work on this platform. "
- "Skipping all symlinking.")
- printed_symlink_error = True
+ for alias, target in aliases.items():
+ symlinkfilename = os.path.join(outdir, alias)
+ self.do_symlink(target, symlinkfilename, outdir)
if file_copied:
self.did_install_something = True
try: