aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/backend/ninjabackend.py4
-rw-r--r--mesonbuild/coredata.py25
-rw-r--r--mesonbuild/scripts/meson_install.py41
4 files changed, 61 insertions, 13 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 8f75dac..bc7c295 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -37,11 +37,13 @@ class CleanTrees:
self.trees = trees
class InstallData:
- def __init__(self, source_dir, build_dir, prefix, strip_bin, mesonintrospect):
+ def __init__(self, source_dir, build_dir, prefix, strip_bin,
+ install_umask, mesonintrospect):
self.source_dir = source_dir
self.build_dir = build_dir
self.prefix = prefix
self.strip_bin = strip_bin
+ self.install_umask = install_umask
self.targets = []
self.headers = []
self.man = []
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index bc3a8ef..fb5b4b7 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -668,7 +668,9 @@ int dummy;
d = InstallData(self.environment.get_source_dir(),
self.environment.get_build_dir(),
self.environment.get_prefix(),
- strip_bin, self.environment.get_build_command() + ['introspect'])
+ strip_bin,
+ self.environment.coredata.get_builtin_option('install_umask'),
+ self.environment.get_build_command() + ['introspect'])
elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY')
elem.add_dep('all')
elem.add_item('DESC', 'Installing files.')
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index ba4f495..17b28a8 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -105,6 +105,22 @@ class UserIntegerOption(UserOption):
except ValueError:
raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
+class UserUmaskOption(UserIntegerOption):
+ def __init__(self, name, description, value, yielding=None):
+ super().__init__(name, description, 0, 0o777, value, yielding)
+
+ def set_value(self, newvalue):
+ if newvalue is None or newvalue == 'preserve':
+ self.value = None
+ else:
+ super().set_value(newvalue)
+
+ def toint(self, valuestring):
+ try:
+ return int(valuestring, 8)
+ except ValueError as e:
+ raise MesonException('Invalid mode: {}'.format(e))
+
class UserComboOption(UserOption):
def __init__(self, name, description, choices, value, yielding=None):
super().__init__(name, description, choices, yielding)
@@ -345,12 +361,12 @@ def is_builtin_option(optname):
def get_builtin_option_choices(optname):
if is_builtin_option(optname):
- if builtin_options[optname][0] == UserStringOption:
- return None
+ if builtin_options[optname][0] == UserComboOption:
+ return builtin_options[optname][2]
elif builtin_options[optname][0] == UserBooleanOption:
return [True, False]
else:
- return builtin_options[optname][2]
+ return None
else:
raise RuntimeError('Tried to get the supported values for an unknown builtin option \'%s\'.' % optname)
@@ -379,6 +395,8 @@ def get_builtin_option_default(optname, prefix='', noneIfSuppress=False):
o = builtin_options[optname]
if o[0] == UserComboOption:
return o[3]
+ if o[0] == UserIntegerOption:
+ return o[4]
if optname in builtin_dir_noprefix_options:
if noneIfSuppress:
# Return None if argparse defaulting should be suppressed for
@@ -438,6 +456,7 @@ builtin_options = {
'backend': [UserComboOption, 'Backend to use.', backendlist, 'ninja'],
'stdsplit': [UserBooleanOption, 'Split stdout and stderr in test logs.', True],
'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True],
+ 'install_umask': [UserUmaskOption, 'Default umask to apply on permissions of installed files.', None],
}
# Special prefix-dependent defaults for installation directories that reside in
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 013f2a0..b454260 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -51,12 +51,25 @@ class DirMaker:
for d in self.dirs:
append_to_log(d)
-def set_mode(path, mode):
- if mode is None:
- # Keep mode unchanged
+def is_executable(path):
+ '''Checks whether any of the "x" bits are set in the source file mode.'''
+ return bool(os.stat(path).st_mode & 0o111)
+
+def sanitize_permissions(path, umask):
+ if umask is None:
return
- if (mode.perms_s or mode.owner or mode.group) is None:
- # Nothing to set
+ new_perms = 0o777 if is_executable(path) else 0o666
+ new_perms &= ~umask
+ try:
+ os.chmod(path, new_perms)
+ except PermissionError as e:
+ msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...'
+ print(msg.format(path, new_perms, e.strerror))
+
+def set_mode(path, mode, default_umask):
+ if mode is None or (mode.perms_s or mode.owner or mode.group) is None:
+ # Just sanitize permissions with the default umask
+ sanitize_permissions(path, default_umask)
return
# No chown() on Windows, and must set one of owner/group
if not is_windows() and (mode.owner or mode.group) is not None:
@@ -83,6 +96,8 @@ def set_mode(path, mode):
except PermissionError as e:
msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...'
print(msg.format(path, mode.perms_s, e.strerror))
+ else:
+ sanitize_permissions(path, default_umask)
def restore_selinux_contexts():
'''
@@ -180,6 +195,7 @@ def do_copydir(data, src_dir, dst_dir, exclude):
sys.exit(1)
data.dirmaker.makedirs(abs_dst)
shutil.copystat(abs_src, abs_dst)
+ sanitize_permissions(abs_dst, data.install_umask)
for f in files:
abs_src = os.path.join(root, f)
filepart = os.path.relpath(abs_src, start=src_dir)
@@ -195,6 +211,7 @@ def do_copydir(data, src_dir, dst_dir, exclude):
os.mkdir(parent_dir)
shutil.copystat(os.path.dirname(abs_src), parent_dir)
shutil.copy2(abs_src, abs_dst, follow_symlinks=False)
+ sanitize_permissions(abs_dst, data.install_umask)
append_to_log(abs_dst)
def get_destdir_path(d, path):
@@ -210,6 +227,8 @@ def do_install(datafilename):
d.destdir = os.environ.get('DESTDIR', '')
d.fullprefix = destdir_join(d.destdir, d.prefix)
+ if d.install_umask is not None:
+ os.umask(d.install_umask)
d.dirmaker = DirMaker()
with d.dirmaker:
install_subdirs(d) # Must be first, because it needs to delete the old subtree.
@@ -226,7 +245,7 @@ def install_subdirs(d):
print('Installing subdir %s to %s' % (src_dir, full_dst_dir))
d.dirmaker.makedirs(full_dst_dir, exist_ok=True)
do_copydir(d, src_dir, full_dst_dir, exclude)
- set_mode(full_dst_dir, mode)
+ set_mode(full_dst_dir, mode, d.install_umask)
def install_data(d):
for i in d.data:
@@ -237,7 +256,7 @@ def install_data(d):
d.dirmaker.makedirs(outdir, exist_ok=True)
print('Installing %s to %s' % (fullfilename, outdir))
do_copyfile(fullfilename, outfilename)
- set_mode(outfilename, mode)
+ set_mode(outfilename, mode, d.install_umask)
def install_man(d):
for m in d.man:
@@ -256,6 +275,7 @@ def install_man(d):
append_to_log(outfilename)
else:
do_copyfile(full_source_filename, outfilename)
+ sanitize_permissions(outfilename, d.install_umask)
def install_headers(d):
for t in d.headers:
@@ -266,6 +286,7 @@ def install_headers(d):
print('Installing %s to %s' % (fname, outdir))
d.dirmaker.makedirs(outdir, exist_ok=True)
do_copyfile(fullfilename, outfilename)
+ sanitize_permissions(outfilename, d.install_umask)
def run_install_script(d):
env = {'MESON_SOURCE_ROOT': d.source_dir,
@@ -330,6 +351,7 @@ def install_targets(d):
raise RuntimeError('File {!r} could not be found'.format(fname))
elif os.path.isfile(fname):
do_copyfile(fname, outname)
+ sanitize_permissions(outname, d.install_umask)
if should_strip and d.strip_bin is not None:
if fname.endswith('.jar'):
print('Not stripping jar target:', os.path.basename(fname))
@@ -346,9 +368,12 @@ def install_targets(d):
pdb_outname = os.path.splitext(outname)[0] + '.pdb'
print('Installing pdb file %s to %s' % (pdb_filename, pdb_outname))
do_copyfile(pdb_filename, pdb_outname)
+ sanitize_permissions(pdb_outname, d.install_umask)
elif os.path.isdir(fname):
fname = os.path.join(d.build_dir, fname.rstrip('/'))
- do_copydir(d, fname, os.path.join(outdir, os.path.basename(fname)), None)
+ outname = os.path.join(outdir, os.path.basename(fname))
+ do_copydir(d, fname, outname, None)
+ sanitize_permissions(outname, d.install_umask)
else:
raise RuntimeError('Unknown file type for {!r}'.format(fname))
printed_symlink_error = False