diff options
-rw-r--r-- | data/syntax-highlighting/vim/syntax/meson.vim | 1 | ||||
-rw-r--r-- | docs/markdown/snippets/install_emptydir.md | 18 | ||||
-rw-r--r-- | docs/yaml/functions/install_emptydir.yaml | 27 | ||||
-rw-r--r-- | docs/yaml/functions/install_subdir.yaml | 9 | ||||
-rw-r--r-- | mesonbuild/ast/interpreter.py | 1 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 15 | ||||
-rw-r--r-- | mesonbuild/build.py | 14 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 13 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreterobjects.py | 3 | ||||
-rw-r--r-- | mesonbuild/minstall.py | 18 | ||||
-rw-r--r-- | test cases/common/246 install_emptydir/meson.build | 4 | ||||
-rw-r--r-- | test cases/common/246 install_emptydir/test.json | 7 |
12 files changed, 125 insertions, 5 deletions
diff --git a/data/syntax-highlighting/vim/syntax/meson.vim b/data/syntax-highlighting/vim/syntax/meson.vim index 15f5232..3a6a7de 100644 --- a/data/syntax-highlighting/vim/syntax/meson.vim +++ b/data/syntax-highlighting/vim/syntax/meson.vim @@ -97,6 +97,7 @@ syn keyword mesonBuiltin \ install_headers \ install_man \ install_subdir + \ install_emptydir \ is_disabler \ is_variable \ jar diff --git a/docs/markdown/snippets/install_emptydir.md b/docs/markdown/snippets/install_emptydir.md new file mode 100644 index 0000000..baedf58 --- /dev/null +++ b/docs/markdown/snippets/install_emptydir.md @@ -0,0 +1,18 @@ +## install_emptydir function + +It is now possible to define a directory which will be created during +installation, without creating it as a side effect of installing files into it. +This replaces custom `meson.add_install_script()` routines. For example: + +```meson +meson.add_install_script('sh', '-c', 'mkdir -p "$DESTDIR/@0@"'.format(path)) +``` + +can be replaced by: + +```meson +install_emptydir(path) +``` + +and as a bonus this works reliably on Windows, prints a sensible progress +message, will be uninstalled by `ninja uninstall`, etc. diff --git a/docs/yaml/functions/install_emptydir.yaml b/docs/yaml/functions/install_emptydir.yaml new file mode 100644 index 0000000..9c874e2 --- /dev/null +++ b/docs/yaml/functions/install_emptydir.yaml @@ -0,0 +1,27 @@ +name: install_emptydir +returns: void +since: 0.60.0 +description: | + Installs a new directory entry to the location specified by the positional + argument. If the directory exists and is not empty, the contents are left in + place. + +varargs: + name: dirpath + type: str + description: Directory to create during installation. + +kwargs: + install_mode: + type: list[str | int] + description: | + Specify the file mode in symbolic format and optionally the owner/uid and + group/gid for the created directory. + + See the `install_mode` kwarg of [[install_data]] for more information. + install_tag: + type: str + description: | + A string used by the `meson install --tags` command to install only a + subset of the files. By default this directory has no install tag which + means it is not installed when the `--tags` argument is specified. diff --git a/docs/yaml/functions/install_subdir.yaml b/docs/yaml/functions/install_subdir.yaml index 83df782..90baed2 100644 --- a/docs/yaml/functions/install_subdir.yaml +++ b/docs/yaml/functions/install_subdir.yaml @@ -5,9 +5,12 @@ description: | source tree to the location specified by the keyword argument `install_dir`. - If the subdirectory does not exist in the source tree, an empty directory is - created in the specified location. *(since 0.45.0)* A newly created - subdirectory may only be created in the keyword argument `install_dir`. + *(since 0.45.0, deprecated since 0.60.0)* If the subdirectory does not exist + in the source tree, an empty directory is created in the specified location. + A newly created subdirectory may only be created in the keyword argument + `install_dir`. There are a number of flaws with this method, and it was never + intentionally designed to work this way, please use [[install_emptydir]] + instead. example: | For a given directory `foo`: diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index 7954b9b..ec93ff5 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -103,6 +103,7 @@ class AstInterpreter(InterpreterBase): 'install_man': self.func_do_nothing, 'install_data': self.func_do_nothing, 'install_subdir': self.func_do_nothing, + 'install_emptydir': self.func_do_nothing, 'configuration_data': self.func_do_nothing, 'configure_file': self.func_do_nothing, 'find_program': self.func_do_nothing, diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 6218156..3d8654e 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -120,6 +120,7 @@ class InstallData: self.targets: T.List[TargetInstallData] = [] self.headers: T.List[InstallDataBase] = [] self.man: T.List[InstallDataBase] = [] + self.emptydir: T.List[InstallEmptyDir] = [] self.data: T.List[InstallDataBase] = [] self.install_scripts: T.List[ExecutableSerialisation] = [] self.install_subdirs: T.List[SubdirInstallData] = [] @@ -147,6 +148,13 @@ class TargetInstallData: self.optional = optional self.tag = tag +class InstallEmptyDir: + def __init__(self, path: str, install_mode: 'FileMode', subproject: str, tag: T.Optional[str] = None): + self.path = path + self.install_mode = install_mode + self.subproject = subproject + self.tag = tag + class InstallDataBase: def __init__(self, path: str, install_path: str, install_path_name: str, install_mode: 'FileMode', subproject: str, tag: T.Optional[str] = None, @@ -1470,6 +1478,7 @@ class Backend: self.generate_target_install(d) self.generate_header_install(d) self.generate_man_install(d) + self.generate_emptydir_install(d) self.generate_data_install(d) self.generate_custom_install_script(d) self.generate_subdir_install(d) @@ -1665,6 +1674,12 @@ class Backend: i = InstallDataBase(srcabs, dstabs, dstname, m.get_custom_install_mode(), m.subproject, tag='man') d.man.append(i) + def generate_emptydir_install(self, d: InstallData) -> None: + emptydir: T.List[build.EmptyDir] = self.build.get_emptydir() + for e in emptydir: + i = InstallEmptyDir(e.path, e.install_mode, e.subproject, e.install_tag) + d.emptydir.append(i) + def generate_data_install(self, d: InstallData) -> None: data = self.build.get_data() srcdir = self.environment.get_source_dir() diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 311732e..ef2210e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -187,6 +187,16 @@ class Man(HoldableObject): return self.sources +class EmptyDir(HoldableObject): + + def __init__(self, path: str, install_mode: 'FileMode', subproject: str, + install_tag: T.Optional[str] = None): + self.path = path + self.install_mode = install_mode + self.subproject = subproject + self.install_tag = install_tag + + class InstallDir(HoldableObject): def __init__(self, src_subdir: str, inst_subdir: str, install_dir: str, @@ -239,6 +249,7 @@ class Build: self.benchmarks: T.List['Test'] = [] self.headers: T.List[Headers] = [] self.man: T.List[Man] = [] + self.emptydir: T.List[EmptyDir] = [] self.data: T.List[Data] = [] self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None) self.subprojects = {} @@ -316,6 +327,9 @@ class Build: def get_data(self) -> T.List['Data']: return self.data + def get_emptydir(self) -> T.List['EmptyDir']: + return self.emptydir + def get_install_subdirs(self) -> T.List['InstallDir']: return self.install_dirs diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 9a89b0c..8ac92c8 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -349,6 +349,7 @@ class Interpreter(InterpreterBase, HoldableObject): 'install_data': self.func_install_data, 'install_headers': self.func_install_headers, 'install_man': self.func_install_man, + 'install_emptydir': self.func_install_emptydir, 'install_subdir': self.func_install_subdir, 'is_disabler': self.func_is_disabler, 'is_variable': self.func_is_variable, @@ -410,6 +411,7 @@ class Interpreter(InterpreterBase, HoldableObject): build.AliasTarget: OBJ.AliasTargetHolder, build.Headers: OBJ.HeadersHolder, build.Man: OBJ.ManHolder, + build.EmptyDir: OBJ.EmptyDirHolder, build.Data: OBJ.DataHolder, build.InstallDir: OBJ.InstallDirHolder, build.IncludeDirs: OBJ.IncludeDirsHolder, @@ -1896,6 +1898,17 @@ This will become a hard error in the future.''' % kwargs['input'], location=self return m + @FeatureNew('install_emptydir', '0.60.0') + @typed_kwargs( + 'install_emptydir', + INSTALL_MODE_KW + ) + def func_install_emptydir(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs) -> None: + d = build.EmptyDir(args[0], kwargs['install_mode'], self.subproject) + self.build.emptydir.append(d) + + return d + @FeatureNewKwargs('subdir', '0.44.0', ['if_found']) @permittedKwargs({'if_found'}) @typed_pos_args('subdir', str) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 072d2f0..b0447e6 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -646,6 +646,9 @@ class InstallDirHolder(ObjectHolder[build.InstallDir]): class ManHolder(ObjectHolder[build.Man]): pass +class EmptyDirHolder(ObjectHolder[build.EmptyDir]): + pass + class GeneratedObjectsHolder(ObjectHolder[build.ExtractedObjects]): pass diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 6284f95..7864742 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -25,7 +25,7 @@ import sys import typing as T from . import environment -from .backend.backends import InstallData, InstallDataBase, TargetInstallData, ExecutableSerialisation +from .backend.backends import InstallData, InstallDataBase, InstallEmptyDir, TargetInstallData, ExecutableSerialisation from .coredata import major_versions_differ, MesonVersionMismatchException from .coredata import version as coredata_version from .mesonlib import Popen_safe, RealPathAction, is_windows @@ -370,7 +370,7 @@ class Installer: return run_exe(*args, **kwargs) return 0 - def should_install(self, d: T.Union[TargetInstallData, InstallDataBase, ExecutableSerialisation]) -> bool: + def should_install(self, d: T.Union[TargetInstallData, InstallEmptyDir, InstallDataBase, 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: @@ -531,6 +531,7 @@ class Installer: self.install_targets(d, dm, destdir, fullprefix) self.install_headers(d, dm, destdir, fullprefix) self.install_man(d, dm, destdir, fullprefix) + self.install_emptydir(d, dm, destdir, fullprefix) self.install_data(d, dm, destdir, fullprefix) self.restore_selinux_contexts(destdir) self.apply_ldconfig(destdir) @@ -581,6 +582,19 @@ class Installer: self.did_install_something = True self.set_mode(outfilename, m.install_mode, d.install_umask) + def install_emptydir(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: + for e in d.emptydir: + if not self.should_install(e): + continue + self.did_install_something = True + full_dst_dir = get_destdir_path(destdir, fullprefix, e.path) + self.log(f'Installing new directory {full_dst_dir}') + if os.path.isfile(full_dst_dir): + print(f'Tried to create directory {full_dst_dir} but a file of that name already exists.') + sys.exit(1) + dm.makedirs(full_dst_dir, exist_ok=True) + self.set_mode(full_dst_dir, e.install_mode, d.install_umask) + def install_headers(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for t in d.headers: if not self.should_install(t): diff --git a/test cases/common/246 install_emptydir/meson.build b/test cases/common/246 install_emptydir/meson.build new file mode 100644 index 0000000..a5eb046 --- /dev/null +++ b/test cases/common/246 install_emptydir/meson.build @@ -0,0 +1,4 @@ +project('install_emptydir') + +install_emptydir(get_option('datadir')/'new_directory', install_mode: 'rwx------') +install_emptydir(get_option('datadir')/'new_directory/subdir', install_mode: 'rwxr-----') diff --git a/test cases/common/246 install_emptydir/test.json b/test cases/common/246 install_emptydir/test.json new file mode 100644 index 0000000..17abe74 --- /dev/null +++ b/test cases/common/246 install_emptydir/test.json @@ -0,0 +1,7 @@ +{ + "installed": [ + { "type": "dir", "file": "usr/share/new_directory" }, + { "type": "dir", "file": "usr/share/new_directory/subdir" } + ] +} + |