Skip to content

Commit

Permalink
fs configure_file_list function
Browse files Browse the repository at this point in the history
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 to `xgettext` 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.
  • Loading branch information
bruchar1 committed Feb 12, 2024
1 parent adf09b8 commit 16ab6e6
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 1 deletion.
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.4.0*

Write paths from a list of files to a configuration file, to be used as argument
to a command. The result file is generated at build time, and is 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 to `xgettext` 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 @@ -62,6 +69,7 @@ def __init__(self, interpreter: 'Interpreter') -> None:
'read': self.read,
'copyfile': self.copyfile,
'relative_to': self.relative_to,
'configure_file_list': self.configure_file_list,
})

def _absolute_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
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.4.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 @@ -168,6 +168,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)

0 comments on commit 16ab6e6

Please sign in to comment.