i18n module: detect gettext tools at configure time

Use this instead of shutil.which to detect whether they will be
available, and pass the ExternalProgram object to CustomTarget
invocations, or else make use of the new functionality to specify the
correct program path in wrapper scripts.

Drop duplicate reporting for itstool missing. Since we use find_program
in required mode, its absence is already fatal, and already has a really
good error description.
pull/10076/head
Eli Schwartz 3 years ago
parent 768616b0f8
commit 08928821ec
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 40
      mesonbuild/modules/i18n.py

@ -11,9 +11,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import annotations
from os import path from os import path
import shutil
import typing as T import typing as T
from . import ExtensionModule, ModuleReturnValue from . import ExtensionModule, ModuleReturnValue
@ -131,15 +131,18 @@ class I18nModule(ExtensionModule):
'gettext': self.gettext, 'gettext': self.gettext,
'itstool_join': self.itstool_join, 'itstool_join': self.itstool_join,
}) })
self.tools: T.Dict[str, T.Optional[ExternalProgram]] = {
'itstool': None,
'msgfmt': None,
'msginit': None,
'msgmerge': None,
'xgettext': None,
}
@staticmethod @staticmethod
def nogettext_warning() -> None: def nogettext_warning() -> None:
mlog.warning('Gettext not found, all translation targets will be ignored.', once=True) mlog.warning('Gettext not found, all translation targets will be ignored.', once=True)
@staticmethod
def noitstool_error() -> T.NoReturn:
raise mesonlib.MesonException('Did not find itstool. Please install it to continue.')
@staticmethod @staticmethod
def _get_data_dirs(state: 'ModuleState', dirs: T.Iterable[str]) -> T.List[str]: def _get_data_dirs(state: 'ModuleState', dirs: T.Iterable[str]) -> T.List[str]:
"""Returns source directories of relative paths""" """Returns source directories of relative paths"""
@ -162,7 +165,9 @@ class I18nModule(ExtensionModule):
KwargInfo('type', str, default='xml', validator=in_set_validator({'xml', 'desktop'})), KwargInfo('type', str, default='xml', validator=in_set_validator({'xml', 'desktop'})),
) )
def merge_file(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'MergeFile') -> ModuleReturnValue: def merge_file(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'MergeFile') -> ModuleReturnValue:
if not shutil.which('xgettext'): if self.tools['msgfmt'] is None:
self.tools['msgfmt'] = state.find_program('msgfmt', required=False, for_machine=mesonlib.MachineChoice.BUILD)
if not self.tools['msgfmt'].found():
self.nogettext_warning() self.nogettext_warning()
return ModuleReturnValue(None, []) return ModuleReturnValue(None, [])
podir = path.join(state.build_to_src, state.subdir, kwargs['po_dir']) podir = path.join(state.build_to_src, state.subdir, kwargs['po_dir'])
@ -175,6 +180,7 @@ class I18nModule(ExtensionModule):
command.extend(state.environment.get_build_command()) command.extend(state.environment.get_build_command())
command.extend([ command.extend([
'--internal', 'msgfmthelper', '--internal', 'msgfmthelper',
'--msgfmt=' + self.tools['msgfmt'].get_path(),
]) ])
if datadirs: if datadirs:
command.append(datadirs) command.append(datadirs)
@ -218,9 +224,13 @@ class I18nModule(ExtensionModule):
), ),
) )
def gettext(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gettext') -> ModuleReturnValue: def gettext(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gettext') -> ModuleReturnValue:
if not shutil.which('xgettext'): for tool in ['msgfmt', 'msginit', 'msgmerge', 'xgettext']:
self.nogettext_warning() if self.tools[tool] is None:
return ModuleReturnValue(None, []) self.tools[tool] = state.find_program(tool, required=False, for_machine=mesonlib.MachineChoice.BUILD)
# still not found?
if not self.tools[tool].found():
self.nogettext_warning()
return ModuleReturnValue(None, [])
packagename = args[0] packagename = args[0]
pkg_arg = f'--pkgname={packagename}' pkg_arg = f'--pkgname={packagename}'
@ -246,6 +256,7 @@ class I18nModule(ExtensionModule):
potargs.append(datadirs) potargs.append(datadirs)
if extra_arg: if extra_arg:
potargs.append(extra_arg) potargs.append(extra_arg)
potargs.append('--xgettext=' + self.tools['xgettext'].get_path())
pottarget = build.RunTarget(packagename + '-pot', potargs, [], state.subdir, state.subproject) pottarget = build.RunTarget(packagename + '-pot', potargs, [], state.subdir, state.subproject)
targets.append(pottarget) targets.append(pottarget)
@ -261,7 +272,7 @@ class I18nModule(ExtensionModule):
f'{packagename}-{l}.mo', f'{packagename}-{l}.mo',
path.join(state.subdir, l, 'LC_MESSAGES'), path.join(state.subdir, l, 'LC_MESSAGES'),
state.subproject, state.subproject,
['msgfmt', '@INPUT@', '-o', '@OUTPUT@'], [self.tools['msgfmt'], '@INPUT@', '-o', '@OUTPUT@'],
[po_file], [po_file],
[f'{packagename}.mo'], [f'{packagename}.mo'],
install=install, install=install,
@ -285,6 +296,8 @@ class I18nModule(ExtensionModule):
updatepoargs.append(datadirs) updatepoargs.append(datadirs)
if extra_arg: if extra_arg:
updatepoargs.append(extra_arg) updatepoargs.append(extra_arg)
for tool in ['msginit', 'msgmerge']:
updatepoargs.append(f'--{tool}=' + self.tools[tool].get_path())
updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs, [], state.subdir, state.subproject) updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs, [], state.subdir, state.subproject)
targets.append(updatepotarget) targets.append(updatepotarget)
@ -305,8 +318,8 @@ class I18nModule(ExtensionModule):
KwargInfo('mo_targets', ContainerTypeInfo(list, build.CustomTarget), required=True), KwargInfo('mo_targets', ContainerTypeInfo(list, build.CustomTarget), required=True),
) )
def itstool_join(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'ItsJoinFile') -> ModuleReturnValue: def itstool_join(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'ItsJoinFile') -> ModuleReturnValue:
if not shutil.which('itstool'): if self.tools['itstool'] is None:
self.noitstool_error() self.tools['itstool'] = state.find_program('itstool', for_machine=mesonlib.MachineChoice.BUILD)
mo_targets = kwargs['mo_targets'] mo_targets = kwargs['mo_targets']
its_files = kwargs.get('its_files', []) its_files = kwargs.get('its_files', [])
@ -320,7 +333,8 @@ class I18nModule(ExtensionModule):
command.extend([ command.extend([
'--internal', 'itstool', 'join', '--internal', 'itstool', 'join',
'-i', '@INPUT@', '-i', '@INPUT@',
'-o', '@OUTPUT@' '-o', '@OUTPUT@',
'--itstool=' + self.tools['itstool'].get_path(),
]) ])
if its_files: if its_files:
for fname in its_files: for fname in its_files:

Loading…
Cancel
Save