modules/fs: Replace configure_file(copy:) with fs.copyfile
`configure_file` is both an extremely complicated implementation, and a strange place for copying. It's a bit of a historical artifact, since the fs module didn't yet exist. It makes more sense to move this to the fs module and deprecate this `configure_file` version. This new version works at build time rather than configure time, which has the disadvantage it can't be passed to `run_command`, but with the advantage that changes to the input don't require a full reconfigure.
This commit is contained in:
parent
f93886192e
commit
991baf56e9
|
@ -215,3 +215,30 @@ fs.stem('foo/bar/baz.dll.a') # baz.dll
|
|||
specified by `path` changes, this will trigger Meson to reconfigure the
|
||||
project. If the file specified by `path` is a `files()` object it
|
||||
cannot refer to a built file.
|
||||
|
||||
|
||||
### copyfile
|
||||
|
||||
*Since 0.64.0*
|
||||
|
||||
Copy a file from the source directory to the build directory at build time
|
||||
|
||||
Has the following positional arguments:
|
||||
- src `File | str`: the file to copy
|
||||
|
||||
Has the following optional arguments:
|
||||
- dest `str`: the name of the output file. If unset will be the basename of
|
||||
the src argument
|
||||
|
||||
Has the following keyword arguments:
|
||||
- install `bool`: Whether to install the copied file, defaults to false
|
||||
- install_dir `str`: Where to install the file to
|
||||
- install_tag: `str`: the install tag to assign to this target
|
||||
- install_mode `array[str | int]`: the mode to install the file with
|
||||
|
||||
returns:
|
||||
- a [[custom_target]] object
|
||||
|
||||
```meson
|
||||
copy = fs.copyfile('input-file', 'output-file')
|
||||
```
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
## `fs.copyfile` to replace `configure_file(copy : true)`
|
||||
|
||||
A new method has been added to the `fs` module, `copyfile`. This method replaces
|
||||
`configure_file(copy : true)`, but only copies files. Unlike `configure_file()`
|
||||
it runs at build time, and the output name is optional defaulting to the
|
||||
filename without paths of the input if unset:
|
||||
|
||||
```meson
|
||||
fs.copyfile('src/file.txt')
|
||||
```
|
||||
Will create a file in the current build directory called `file.txt`
|
||||
|
||||
|
||||
```meson
|
||||
fs.copyfile('file.txt', 'outfile.txt')
|
||||
```
|
||||
Will create a copy renamed to `outfile.txt`
|
|
@ -2453,7 +2453,10 @@ class Interpreter(InterpreterBase, HoldableObject):
|
|||
'configuration',
|
||||
(ContainerTypeInfo(dict, (str, int, bool)), build.ConfigurationData, NoneType),
|
||||
),
|
||||
KwargInfo('copy', bool, default=False, since='0.47.0'),
|
||||
KwargInfo(
|
||||
'copy', bool, default=False, since='0.47.0',
|
||||
deprecated='0.64.0', deprecated_message='Use fs.copy instead',
|
||||
),
|
||||
KwargInfo('encoding', str, default='utf-8', since='0.47.0'),
|
||||
KwargInfo('format', str, default='meson', since='0.46.0',
|
||||
validator=in_set_validator({'meson', 'cmake', 'cmake@'})),
|
||||
|
|
|
@ -12,24 +12,28 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import typing as T
|
||||
from __future__ import annotations
|
||||
from pathlib import Path, PurePath, PureWindowsPath
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path, PurePath, PureWindowsPath
|
||||
import typing as T
|
||||
|
||||
from . import ExtensionModule, ModuleReturnValue, ModuleInfo
|
||||
from .. import mlog
|
||||
from . import ExtensionModule, ModuleInfo
|
||||
from ..build import CustomTarget, 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,
|
||||
)
|
||||
from ..interpreterbase import FeatureNew, KwargInfo, typed_kwargs, typed_pos_args, noKwargs
|
||||
|
||||
if T.TYPE_CHECKING:
|
||||
from . import ModuleState
|
||||
from ..interpreter import Interpreter
|
||||
from ..mesonlib import FileOrString
|
||||
from ..mesonlib import FileOrString, FileMode
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
|
@ -38,6 +42,15 @@ if T.TYPE_CHECKING:
|
|||
|
||||
encoding: str
|
||||
|
||||
class CopyKw(TypedDict):
|
||||
|
||||
"""Kwargs for fs.copy"""
|
||||
|
||||
install: bool
|
||||
install_dir: T.Optional[str]
|
||||
install_mode: FileMode
|
||||
install_tag: T.Optional[str]
|
||||
|
||||
|
||||
class FSModule(ExtensionModule):
|
||||
|
||||
|
@ -61,6 +74,7 @@ class FSModule(ExtensionModule):
|
|||
'name': self.name,
|
||||
'stem': self.stem,
|
||||
'read': self.read,
|
||||
'copyfile': self.copyfile,
|
||||
})
|
||||
|
||||
def _absolute_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
|
||||
|
@ -255,6 +269,47 @@ class FSModule(ExtensionModule):
|
|||
self.interpreter.add_build_def_file(path)
|
||||
return data
|
||||
|
||||
@FeatureNew('fs.copyfile', '0.64.0')
|
||||
@typed_pos_args('fs.copyfile', (File, str), optargs=[str])
|
||||
@typed_kwargs(
|
||||
'fs.copyfile',
|
||||
INSTALL_KW,
|
||||
INSTALL_MODE_KW,
|
||||
INSTALL_TAG_KW,
|
||||
KwargInfo('install_dir', (str, NoneType)),
|
||||
)
|
||||
def copyfile(self, state: ModuleState, args: T.Tuple[FileOrString, T.Optional[str]],
|
||||
kwargs: CopyKw) -> ModuleReturnValue:
|
||||
"""Copy a file into the build directory at build time."""
|
||||
if kwargs['install'] and not kwargs['install_dir']:
|
||||
raise InvalidArguments('"install_dir" must be specified when "install" is true')
|
||||
|
||||
src = self.interpreter.source_strings_to_files([args[0]])[0]
|
||||
|
||||
# The input is allowed to have path separators, but the output may not,
|
||||
# so use the basename for the default case
|
||||
dest = args[1] if args[1] else os.path.basename(src.fname)
|
||||
if has_path_sep(dest):
|
||||
raise InvalidArguments('Destination path may not have path separators')
|
||||
|
||||
ct = CustomTarget(
|
||||
dest,
|
||||
state.subdir,
|
||||
state.subproject,
|
||||
state.environment,
|
||||
state.environment.get_build_command() + ['--internal', 'copy', '@INPUT@', '@OUTPUT@'],
|
||||
[src],
|
||||
[dest],
|
||||
build_by_default=True,
|
||||
install=kwargs['install'],
|
||||
install_dir=kwargs['install_dir'],
|
||||
install_mode=kwargs['install_mode'],
|
||||
install_tag=kwargs['install_tag'],
|
||||
backend=state.backend,
|
||||
)
|
||||
|
||||
return ModuleReturnValue(ct, [ct])
|
||||
|
||||
|
||||
def initialize(*args: T.Any, **kwargs: T.Any) -> FSModule:
|
||||
return FSModule(*args, **kwargs)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
project('configure file test', 'c', meson_version: '>=0.47.0')
|
||||
project('configure file test', 'c', meson_version: '>=0.63.0')
|
||||
|
||||
fs = import('fs')
|
||||
|
||||
conf = configuration_data()
|
||||
|
||||
|
@ -188,6 +190,9 @@ if ret.returncode() != 0
|
|||
endif
|
||||
# Now the same, but using a File object as an argument.
|
||||
inf2 = files('invalid-utf8.bin.in')[0]
|
||||
outf = configure_file(input : inf2,
|
||||
output : 'invalid-utf8.bin',
|
||||
copy: true)
|
||||
ret = run_command(check_file, inf2, outf, check: false)
|
||||
if ret.returncode() != 0
|
||||
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||
|
@ -202,6 +207,21 @@ if ret.returncode() != 0
|
|||
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||
endif
|
||||
|
||||
# Test the fs replacement
|
||||
# Test copying of an empty configuration data object
|
||||
inf = 'invalid-utf8.bin.in'
|
||||
outf = fs.copyfile(inf, 'invalid-utf8-1.bin')
|
||||
test('fs.copyfile string', check_file, args: [files(inf), outf])
|
||||
|
||||
# Test with default outname of string
|
||||
outf = fs.copyfile(inf)
|
||||
test('fs.copyfile default name', check_file, args: [files(inf), outf])
|
||||
|
||||
# Now the same, but using a File object as an argument.
|
||||
inf2 = files('invalid-utf8.bin.in')[0]
|
||||
outf = fs.copyfile(inf2, 'invalid-utf8-2.bin')
|
||||
test('fs.copyfile file', check_file, args: [inf2, outf])
|
||||
|
||||
# Test non isolatin1 encoded input file which fails to decode with utf-8
|
||||
conf8 = configuration_data()
|
||||
conf8.set('var', 'foo')
|
||||
|
|
Loading…
Reference in New Issue