diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 7f7ab43ff..943c087ac 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -227,6 +227,9 @@ def run_script_command(args): elif cmdname == 'gettext': import mesonbuild.scripts.gettext as abc cmdfunc = abc.run + elif cmdname == 'yelphelper': + import mesonbuild.scripts.yelphelper as abc + cmdfunc = abc.run else: raise MesonException('Unknown internal command {}.'.format(cmdname)) return cmdfunc(cmdargs) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index bb6abd426..0a1d916ef 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -17,6 +17,7 @@ functionality such as gobject-introspection and gresources.''' from .. import build import os +import sys import subprocess from ..mesonlib import MesonException from .. import dependencies @@ -461,6 +462,65 @@ class GnomeModule: target_g = build.CustomTarget(targetname, state.subdir, kwargs) return target_g + def yelp(self, state, args, kwargs): + if len(args) < 1: + raise MesonException('Yelp requires a project id') + + project_id = args[0] + sources = mesonlib.stringlistify(kwargs.pop('sources', [])) + if not sources: + if len(args) > 1: + sources = mesonlib.stringlistify(args[1:]) + if not sources: + raise MesonException('Yelp requires a list of sources') + source_str = '@@'.join(sources) + + langs = mesonlib.stringlistify(kwargs.pop('languages', [])) + media = mesonlib.stringlistify(kwargs.pop('media', [])) + symlinks = kwargs.pop('symlink_media', False) + + if not isinstance(symlinks, bool): + raise MesonException('symlink_media must be a boolean') + + if kwargs: + raise MesonException('Unknown arguments passed: {}'.format(', '.join(kwargs.keys()))) + + install_cmd = [ + sys.executable, + state.environment.get_build_command(), + '--internal', + 'yelphelper', + 'install', + '--subdir=' + state.subdir, + '--id=' + project_id, + '--installdir=' + os.path.join(state.environment.get_datadir(), 'help'), + '--sources=' + source_str, + ] + if symlinks: + install_cmd.append('--symlinks=true') + if media: + install_cmd.append('--media=' + '@@'.join(media)) + if langs: + install_cmd.append('--langs=' + '@@'.join(langs)) + inscript = build.InstallScript(install_cmd) + + potargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'pot', + '--subdir=' + state.subdir, + '--id=' + project_id, + '--sources=' + source_str] + pottarget = build.RunTarget('help-' + project_id + '-pot', sys.executable, + potargs, [], state.subdir) + + poargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'update-po', + '--subdir=' + state.subdir, + '--id=' + project_id, + '--sources=' + source_str, + '--langs=' + '@@'.join(langs)] + potarget = build.RunTarget('help-' + project_id + '-update-po', sys.executable, + poargs, [], state.subdir) + + return [inscript, pottarget, potarget] + def gtkdoc(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gtkdoc must have one positional argument.') diff --git a/mesonbuild/scripts/yelphelper.py b/mesonbuild/scripts/yelphelper.py new file mode 100644 index 000000000..00d713af1 --- /dev/null +++ b/mesonbuild/scripts/yelphelper.py @@ -0,0 +1,118 @@ +# Copyright 2016 Patrick Griffis + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys, os +import subprocess +import shutil +import argparse +from mesonbuild import mlog +from mesonbuild.mesonlib import MesonException +from mesonbuild.scripts import destdir_join + +parser = argparse.ArgumentParser() +parser.add_argument('command') +parser.add_argument('--id', dest='project_id') +parser.add_argument('--subdir', dest='subdir') +parser.add_argument('--installdir', dest='install_dir') +parser.add_argument('--sources', dest='sources') +parser.add_argument('--media', dest='media', default='') +parser.add_argument('--langs', dest='langs', default='') +parser.add_argument('--symlinks', type=bool, dest='symlinks', default=False) + +def build_pot(srcdir, project_id, sources): + # Must be relative paths + sources = [os.path.join('C', source) for source in sources] + outfile = os.path.join(srcdir, project_id + '.pot') + subprocess.call(['itstool', '-o', outfile, *sources]) + +def update_po(srcdir, project_id, langs): + potfile = os.path.join(srcdir, project_id + '.pot') + for lang in langs: + pofile = os.path.join(srcdir, lang, lang + '.po') + subprocess.call(['msgmerge', '-q', '-o', pofile, pofile, potfile]) + +def build_translations(srcdir, blddir, langs): + for lang in langs: + outdir = os.path.join(blddir, lang) + os.makedirs(outdir, exist_ok=True) + subprocess.call([ + 'msgfmt', os.path.join(srcdir, lang, lang + '.po'), + '-o', os.path.join(outdir, lang + '.gmo') + ]) + +def merge_translations(blddir, sources, langs): + for lang in langs: + subprocess.call([ + 'itstool', '-m', os.path.join(blddir, lang, lang + '.gmo'), + '-o', os.path.join(blddir, lang), + *sources, + ]) + +def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, project_id, symlinks): + c_install_dir = os.path.join(install_dir, 'C', project_id) + for lang in langs + ['C']: + indir = destdir_join(destdir, os.path.join(install_dir, lang, project_id)) + os.makedirs(indir, exist_ok=True) + for source in sources: + infile = os.path.join(srcdir if lang == 'C' else blddir, lang, source) + outfile = os.path.join(indir, source) + mlog.log('Installing %s to %s.' %(infile, outfile)) + shutil.copyfile(infile, outfile) + shutil.copystat(infile, outfile) + for m in media: + infile = os.path.join(srcdir, lang, m) + outfile = os.path.join(indir, m) + if not os.path.exists(infile): + if lang == 'C': + mlog.log(mlog.bold('Warning:'), 'Media file "%s" did not exist in C directory' %m) + elif symlinks: + srcfile = os.path.join(c_install_dir, m) + mlog.log('Symlinking %s to %s.' %(outfile, srcfile)) + if '/' in m or '\\' in m: + os.makedirs(os.path.dirname(outfile), exist_ok=True) + os.symlink(srcfile, outfile) + continue + symfile = os.path.join(install_dir, m) + mlog.log('Installing %s to %s.' %(infile, outfile)) + if '/' in m or '\\' in m: + os.makedirs(os.path.dirname(outfile), exist_ok=True) + shutil.copyfile(infile, outfile) + shutil.copystat(infile, outfile) + +def run(args): + options = parser.parse_args(args) + langs = options.langs.split('@@') if options.langs else [] + media = options.media.split('@@') if options.media else [] + sources = options.sources.split('@@') + destdir = os.environ.get('DESTDIR', '') + src_subdir = os.path.join(os.environ['MESON_SOURCE_ROOT'], options.subdir) + build_subdir = os.path.join(os.environ['MESON_BUILD_ROOT'], options.subdir) + abs_sources = [os.path.join(src_subdir, 'C', source) for source in sources] + + if options.command == 'pot': + build_pot(src_subdir, options.project_id, sources) + elif options.command == 'update-po': + build_pot(src_subdir, options.project_id, sources) + update_po(src_subdir, options.project_id, langs) + elif options.command == 'build': + if langs: + build_translations(src_subdir, build_subdir, langs) + elif options.command == 'install': + install_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], options.install_dir) + if langs: + build_translations(src_subdir, build_subdir, langs) + merge_translations(build_subdir, abs_sources, langs) + install_help(src_subdir, build_subdir, sources, media, langs, install_dir, + destdir, options.project_id, options.symlinks) + diff --git a/test cases/frameworks/13 yelp/help/C/index.page b/test cases/frameworks/13 yelp/help/C/index.page new file mode 100644 index 000000000..1b367e678 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/C/index.page @@ -0,0 +1,8 @@ + + + Hello! + + diff --git a/test cases/frameworks/13 yelp/help/C/media/test.txt b/test cases/frameworks/13 yelp/help/C/media/test.txt new file mode 100644 index 000000000..ce0136250 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/C/media/test.txt @@ -0,0 +1 @@ +hello diff --git a/test cases/frameworks/13 yelp/help/de/de.po b/test cases/frameworks/13 yelp/help/de/de.po new file mode 100644 index 000000000..a54ce7fda --- /dev/null +++ b/test cases/frameworks/13 yelp/help/de/de.po @@ -0,0 +1,13 @@ +msgid "" +msgstr "" +"Project-Id-Version: meson master\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. (itstool) path: page/title +#: C/index.page:5 +msgid "Hello!" +msgstr "Hallo!" diff --git a/test cases/frameworks/13 yelp/help/es/es.po b/test cases/frameworks/13 yelp/help/es/es.po new file mode 100644 index 000000000..b69ce7fc3 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/es/es.po @@ -0,0 +1,13 @@ +msgid "" +msgstr "" +"Project-Id-Version: meson master\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. (itstool) path: page/title +#: C/index.page:5 +msgid "Hello!" +msgstr "¡Hola!" diff --git a/test cases/frameworks/13 yelp/help/es/media/test.txt b/test cases/frameworks/13 yelp/help/es/media/test.txt new file mode 100644 index 000000000..3453b0015 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/es/media/test.txt @@ -0,0 +1 @@ +Hola. diff --git a/test cases/frameworks/13 yelp/help/meson.build b/test cases/frameworks/13 yelp/help/meson.build new file mode 100644 index 000000000..7c6f01d90 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/meson.build @@ -0,0 +1,7 @@ +gnome = import('gnome') + +gnome.yelp('meson', + sources: 'index.page', + media: 'media/test.txt', + languages: ['de', 'es'], +) diff --git a/test cases/frameworks/13 yelp/installed_files.txt b/test cases/frameworks/13 yelp/installed_files.txt new file mode 100644 index 000000000..59d21585e --- /dev/null +++ b/test cases/frameworks/13 yelp/installed_files.txt @@ -0,0 +1,5 @@ +usr/share/help/C/meson/index.page +usr/share/help/C/meson/media/test.txt +usr/share/help/es/meson/index.page +usr/share/help/es/meson/media/test.txt +usr/share/help/de/meson/index.page diff --git a/test cases/frameworks/13 yelp/meson.build b/test cases/frameworks/13 yelp/meson.build new file mode 100644 index 000000000..725ff7b1b --- /dev/null +++ b/test cases/frameworks/13 yelp/meson.build @@ -0,0 +1,2 @@ +project('yelp', 'c') +subdir('help')