Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs configure_file_list function #12272

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/markdown/Fs-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,32 @@ returns:
```meson
copy = fs.copyfile('input-file', 'output-file')
```

### configure_file_list

*Since 1.7.0*

Write paths from a list of files to a configuration file, which can be used as
an argument to a command. The result file is generated at build time and
updated when any input file is updated.

Has the following positional arguments:
- name `str`: name of the resulting file
- sources `str | file | custom_tgt | custom_idx | build_tgt`: file paths to
write to the result file

Has the following keyword arguments:
- quote `bool`: if `true`, add quote and escape chars to the file paths
(default `false`)
- separator `str`: characters used to separate the paths (default `\n`)
- end `str`: characters to put at the end of the file (default `\n`)
- relative_paths `bool`: if `true`, write relative paths, if `false`, write
absolute paths (default: `false`)

returns:
- a [[custom_target]] object

```meson
src_files = files(...)
file_list = fs.configure_file_list('filelist.txt', src_files)
```
7 changes: 7 additions & 0 deletions docs/markdown/snippets/fs_configure_file_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## `fs.configure_file_list()`

This function produces, at build time, a file containing the list of files given
as argument. It is used when a command uses, as argument, a file containing the
list of files to process. One usecase is to provide `xgettext` with the list of
files to process, from the list of source files, when this list is too long to
be provided to the command line as individual files.
73 changes: 72 additions & 1 deletion mesonbuild/modules/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from ..build import BuildTarget, CustomTarget, CustomTargetIndex, InvalidArguments
from ..interpreter.type_checking import INSTALL_KW, INSTALL_MODE_KW, INSTALL_TAG_KW, NoneType
from ..interpreterbase import FeatureNew, KwargInfo, typed_kwargs, typed_pos_args, noKwargs
from ..mesonlib import File, MesonException, has_path_sep, path_is_in_root, relpath
from ..mesonlib import File, MesonException, has_path_sep, path_is_in_root, relpath, quote_arg

if T.TYPE_CHECKING:
from . import ModuleState
Expand All @@ -37,6 +37,13 @@ class CopyKw(TypedDict):
install_mode: FileMode
install_tag: T.Optional[str]

class ConfigureFileListKw(TypedDict):

quote: bool
separator: str
end: str
relative_paths: bool


class FSModule(ExtensionModule):

Expand All @@ -46,6 +53,7 @@ def __init__(self, interpreter: 'Interpreter') -> None:
super().__init__(interpreter)
self.methods.update({
'as_posix': self.as_posix,
'configure_file_list': self.configure_file_list,
'copyfile': self.copyfile,
'exists': self.exists,
'expanduser': self.expanduser,
Expand Down Expand Up @@ -317,6 +325,69 @@ def to_path(arg: T.Union[FileOrString, CustomTarget, CustomTargetIndex, BuildTar

return relpath(t, f)

@FeatureNew('fs.configure_file_list', '1.7.0')
@typed_pos_args('fs.configure_file_list', str, varargs=(str, File, CustomTarget, CustomTargetIndex, BuildTarget))
@typed_kwargs(
'fs.configure_file_list',
KwargInfo('quote', bool, default=False),
KwargInfo('separator', str, default='\n'),
KwargInfo('end', str, default='\n'),
KwargInfo('relative_paths', bool, default=False),
)
def configure_file_list(self, state: ModuleState, args: T.Tuple[str, T.List[T.Union[FileOrString, BuildTargetTypes]]], kwargs: ConfigureFileListKw) -> ModuleReturnValue:
current_build_dir = Path(state.environment.build_dir, state.subdir)
file_list_dir = current_build_dir / 'file_list.p'
file_list_dir.mkdir(exist_ok=True)
name = args[0]

input_file = file_list_dir / name
output_file = current_build_dir / name

separator = kwargs['separator']
is_relative = kwargs['relative_paths']
quote = kwargs['quote']

# We generate the output now because we know how...
sources = args[1].copy()
nargs = len(sources)
with input_file.open('w', encoding='utf-8') as f:
for i, a in enumerate(sources, 1):
if isinstance(a, str):
a = File(False, state.subdir, a)

elif isinstance(a, (BuildTarget, CustomTarget, CustomTargetIndex)):
a = File(True, a.get_subdir(), a.get_outputs()[0])

assert isinstance(a, File), 'for mypy'
if is_relative:
line = a.relative_name()
else:
line = a.absolute_path(state.environment.source_dir, state.environment.build_dir)

if quote:
line = quote_arg(line)

if i == nargs:
separator = kwargs['end']
print(line, end=separator, file=f)

sources.insert(0, input_file.as_posix())

# ...but we copy it later, to ensure it is touched when an input is modified
ct = CustomTarget(
name,
state.subdir,
state.subproject,
state.environment,
state.environment.get_build_command() + ['--internal', 'copy', '@INPUT0@', '@OUTPUT@'],
sources,
[output_file.name],
build_by_default=True,
backend=state.backend,
description='Generating file list {}',
)
return ModuleReturnValue(ct, [ct])


def initialize(*args: T.Any, **kwargs: T.Any) -> FSModule:
return FSModule(*args, **kwargs)
15 changes: 15 additions & 0 deletions test cases/common/220 fs module/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,21 @@ subdir('subdir')

subproject('subbie')


# configure_file_list
test_file_list = find_program('testfilelist.py')
cfl = fs.configure_file_list(
'fl.txt',
'meson.build',
subdirfiles,
[btgt, ctgt],
)
test(
'fs.configure_file_list',
test_file_list,
args: cfl,
)

testcase expect_error('File notfound does not exist.')
fs.read('notfound')
endtestcase
16 changes: 16 additions & 0 deletions test cases/common/220 fs module/testfilelist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python3

import sys
from pathlib import Path

input_file = Path(sys.argv[-1])
if not input_file.exists():
sys.exit('Input file not found')

with input_file.open('r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not Path(line).exists():
sys.exit(f'File {line} not found')

sys.exit(0)
Loading