Allow excluding files from `install_subdir`

The install_subdir command now accepts a new `exclude` keyword argument
that allows specified files to be excluded from the installed
subdirectory.
pull/1968/head
Elliott Sales de Andrade 8 years ago
parent 58bd1e83b4
commit 5cb1d00537
  1. 10
      docs/markdown/Reference-manual.md
  2. 6
      docs/markdown/Release-notes-for-0.42.0.md
  3. 2
      mesonbuild/backend/ninjabackend.py
  4. 33
      mesonbuild/interpreter.py
  5. 20
      mesonbuild/scripts/meson_install.py
  6. 2
      test cases/common/66 install subdir/installed_files.txt
  7. 6
      test cases/common/66 install subdir/meson.build
  8. 0
      test cases/common/66 install subdir/sub2/dircheck/excluded-three.dat
  9. 0
      test cases/common/66 install subdir/sub2/excluded-three.dat
  10. 0
      test cases/common/66 install subdir/sub2/excluded/two.dat
  11. 0
      test cases/common/66 install subdir/sub2/one.dat

@ -474,11 +474,19 @@ Installs the specified man files from the source tree into system's man director
### install_subdir()
``` meson
void install_subdir(subdir_name)
void install_subdir(subdir_name, install_dir : ..., exclude_files : ..., exclude_directories : ...)
```
Installs the entire given subdirectory and its contents from the source tree to the location specified by the keyword argument `install_dir`. Note that due to implementation issues this command deletes the entire target dir before copying the files, so you should never use `install_subdir` to install into two overlapping directories (such as `foo` and `foo/bar`) because if you do the behavior is undefined.
The following keyword arguments are supported:
- `install_dir`: the location to place the installed subdirectory.
- `exclude_files`: a list of file names that should not be installed.
Names are interpreted as paths relative to the `subdir_name` location.
- `exclude_directories`: a list of directory names that should not be installed.
Names are interpreted as paths relative to the `subdir_name` location.
### is_variable()
``` meson

@ -104,3 +104,9 @@ By default Meson adds the current source and build directories to the
header search path. On some rare occasions this is not desired. Setting
the `implicit_include_directories` keyword argument to `false` these
directories are not used.
## Allow excluding files or directories from `install_subdir`
The [`install_subdir`](Reference-manual.md#install_subdir) command accepts the
new `exclude_files` and `exclude_directories` keyword arguments that allow
specified files or directories to be excluded from the installed subdirectory.

@ -813,7 +813,7 @@ int dummy;
inst_dir = sd.installable_subdir
src_dir = os.path.join(self.environment.get_source_dir(), subdir)
dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir)
d.install_subdirs.append([src_dir, inst_dir, dst_dir, sd.install_mode])
d.install_subdirs.append([src_dir, inst_dir, dst_dir, sd.install_mode, sd.exclude])
def generate_tests(self, outfile):
self.serialize_tests()

@ -456,12 +456,13 @@ class DataHolder(InterpreterObject):
return self.held_object.install_dir
class InstallDir(InterpreterObject):
def __init__(self, src_subdir, inst_subdir, install_dir, install_mode):
def __init__(self, src_subdir, inst_subdir, install_dir, install_mode, exclude):
InterpreterObject.__init__(self)
self.source_subdir = src_subdir
self.installable_subdir = inst_subdir
self.install_dir = install_dir
self.install_mode = install_mode
self.exclude = exclude
class Man(InterpreterObject):
@ -1297,7 +1298,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'install_data': {'install_dir', 'install_mode', 'sources'},
'install_headers': {'install_dir', 'subdir'},
'install_man': {'install_dir'},
'install_subdir': {'install_dir', 'install_mode'},
'install_subdir': {'exclude_files', 'exclude_directories', 'install_dir', 'install_mode'},
'jar': jar_kwargs,
'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'},
'run_target': {'command', 'depends'},
@ -2442,13 +2443,39 @@ class Interpreter(InterpreterBase):
def func_install_subdir(self, node, args, kwargs):
if len(args) != 1:
raise InvalidArguments('Install_subdir requires exactly one argument.')
subdir = args[0]
if 'install_dir' not in kwargs:
raise InvalidArguments('Missing keyword argument install_dir')
install_dir = kwargs['install_dir']
if not isinstance(install_dir, str):
raise InvalidArguments('Keyword argument install_dir not a string.')
if 'exclude_files' in kwargs:
exclude = kwargs['exclude_files']
if not isinstance(exclude, list):
exclude = [exclude]
for f in exclude:
if not isinstance(f, str):
raise InvalidArguments('Exclude argument not a string.')
elif os.path.isabs(f):
raise InvalidArguments('Exclude argument cannot be absolute.')
exclude_files = {os.path.join(subdir, f) for f in exclude}
else:
exclude_files = set()
if 'exclude_directories' in kwargs:
exclude = kwargs['exclude_directories']
if not isinstance(exclude, list):
exclude = [exclude]
for d in exclude:
if not isinstance(d, str):
raise InvalidArguments('Exclude argument not a string.')
elif os.path.isabs(d):
raise InvalidArguments('Exclude argument cannot be absolute.')
exclude_directories = {os.path.join(subdir, f) for f in exclude}
else:
exclude_directories = set()
exclude = (exclude_files, exclude_directories)
install_mode = self._get_kwarg_install_mode(kwargs)
idir = InstallDir(self.subdir, args[0], install_dir, install_mode)
idir = InstallDir(self.subdir, subdir, install_dir, install_mode, exclude)
self.build.install_dirs.append(idir)
return idir

@ -128,17 +128,25 @@ def do_copyfile(from_file, to_file):
restore_selinux_context(to_file)
append_to_log(to_file)
def do_copydir(data, src_prefix, src_dir, dst_dir):
def do_copydir(data, src_prefix, src_dir, dst_dir, exclude):
'''
Copies the directory @src_prefix (full path) into @dst_dir
@src_dir is simply the parent directory of @src_prefix
'''
if exclude is not None:
exclude_files, exclude_dirs = exclude
else:
exclude_files = exclude_dirs = set()
for root, dirs, files in os.walk(src_prefix):
for d in dirs:
for d in dirs[:]:
abs_src = os.path.join(src_dir, root, d)
filepart = abs_src[len(src_dir) + 1:]
abs_dst = os.path.join(dst_dir, filepart)
# Remove these so they aren't visited by os.walk at all.
if filepart in exclude_dirs:
dirs.remove(d)
continue
if os.path.isdir(abs_dst):
continue
if os.path.exists(abs_dst):
@ -149,6 +157,8 @@ def do_copydir(data, src_prefix, src_dir, dst_dir):
for f in files:
abs_src = os.path.join(src_dir, root, f)
filepart = abs_src[len(src_dir) + 1:]
if filepart in exclude_files:
continue
abs_dst = os.path.join(dst_dir, filepart)
if os.path.isdir(abs_dst):
print('Tried to copy file %s but a directory of that name already exists.' % abs_dst)
@ -184,14 +194,14 @@ def do_install(datafilename):
run_install_script(d)
def install_subdirs(d):
for (src_dir, inst_dir, dst_dir, mode) in d.install_subdirs:
for (src_dir, inst_dir, dst_dir, mode, exclude) in d.install_subdirs:
if src_dir.endswith('/') or src_dir.endswith('\\'):
src_dir = src_dir[:-1]
src_prefix = os.path.join(src_dir, inst_dir)
print('Installing subdir %s to %s' % (src_prefix, dst_dir))
dst_dir = get_destdir_path(d, dst_dir)
d.dirmaker.makedirs(dst_dir, exist_ok=True)
do_copydir(d, src_prefix, src_dir, dst_dir)
do_copydir(d, src_prefix, src_dir, dst_dir, exclude)
dst_prefix = os.path.join(dst_dir, inst_dir)
set_mode(dst_prefix, mode)
@ -317,7 +327,7 @@ def install_targets(d):
do_copyfile(pdb_filename, pdb_outname)
elif os.path.isdir(fname):
fname = os.path.join(d.build_dir, fname.rstrip('/'))
do_copydir(d, fname, os.path.dirname(fname), outdir)
do_copydir(d, fname, os.path.dirname(fname), outdir, None)
else:
raise RuntimeError('Unknown file type for {!r}'.format(fname))
printed_symlink_error = False

@ -2,3 +2,5 @@ usr/share/sub1/data1.dat
usr/share/sub1/second.dat
usr/share/sub1/third.dat
usr/share/sub1/sub2/data2.dat
usr/share/sub2/one.dat
usr/share/sub2/dircheck/excluded-three.dat

@ -1,5 +1,11 @@
project('install a whole subdir', 'c')
# A subdir with an exclusion:
install_subdir('sub2',
exclude_files : ['excluded-three.dat'],
exclude_directories : ['excluded'],
install_dir : 'share')
subdir('subdir')
# A subdir with write perms only for the owner
# and read-list perms for owner and group

Loading…
Cancel
Save