[gtkmm-documentation/gtkmm-3-24] Meson build: Don't use gnome.yelp()



commit c4e03959616eb91663e65dc6103532c112b8b2fe
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Tue Feb 22 15:12:27 2022 +0100

    Meson build: Don't use gnome.yelp()
    
    In Meson >= 0.61.0, gnome.yelp() can't be used on a generated
    XML file. See https://github.com/mesonbuild/meson/issues/10017

 docs/tutorial/meson.build              |  86 ++++++++++++++++++------
 tools/meson_aux/extra-dist-cmd.py      |  20 +++---
 tools/meson_aux/tutorial-custom-cmd.py | 118 ++++++++++++++++++++++++++++++---
 3 files changed, 185 insertions(+), 39 deletions(-)
---
diff --git a/docs/tutorial/meson.build b/docs/tutorial/meson.build
index c5aa5db..407606c 100644
--- a/docs/tutorial/meson.build
+++ b/docs/tutorial/meson.build
@@ -1,6 +1,6 @@
 # docs/tutorial
 
-# input: gnome, install_datadir, gtkmm_pcname, tutorial_custom_cmd,
+# input: install_datadir, gtkmm_pcname, tutorial_custom_cmd,
 #        project_source_root, python3
 # output: can_parse_and_validate, build_translations_by_default, can_build_translations,
 #         build_pdf_by_default, can_build_pdf, tutorialdir
@@ -41,10 +41,12 @@ can_build_pdf = dblatex.found() or (xsltproc.found() and \
 build_pdf_by_default = get_option('build-pdf')
 
 # Installation directories are relative to {prefix}.
+gtkmm_tutorial = 'gtkmm-tutorial'
 tutorialdir = install_datadir / 'doc' / gtkmm_pcname / 'tutorial'
 tutorial_htmldir = tutorialdir / 'html'
 tutorial_figuresdir = tutorial_htmldir / 'figures'
 tutorial_iconsdir = tutorial_htmldir / 'icons'
+tutorial_C_xmldir = install_datadir / 'help' / 'C' / gtkmm_tutorial
 
 tutorial_figurefiles = [
   'alignment.png',
@@ -158,8 +160,22 @@ foreach i : tutorial_iconfiles
   tutorial_icons += 'icons' / i
 endforeach
 
+if can_build_translations and build_translations_by_default
+  # Get a list of translated languages.
+  language_obj = run_command(
+    python3, tutorial_custom_cmd, 'get_languages',
+    meson.current_source_dir(),
+    check: false,
+  )
+  if language_obj.stderr() != ''
+    warning(language_obj.stderr())
+  endif
+  languages = language_obj.stdout().split()
+else
+  languages = []
+endif
+
 # Create a DocBook C locale XML file with the examples' source code included.
-# Copy it to the source directory, where gnome.yelp() expects to find it.
 index_docbook = custom_target('index.docbook',
   input: 'C' / 'index-in.docbook',
   output: 'index.docbook',
@@ -170,9 +186,14 @@ index_docbook = custom_target('index.docbook',
     '@INPUT@',
     '@OUTPUT@',
   ],
-  build_by_default: true
+  build_by_default: true,
+  install: true,
+  install_dir: tutorial_C_xmldir,
 )
 
+# Install extra files in the C locale XML file directory.
+install_data(tutorial_C_figures, install_dir: tutorial_C_xmldir / 'figures')
+
 # Create an html version of the C locale's version of the DocBook.
 custom_target('html_index.html',
   input: index_docbook,
@@ -187,6 +208,11 @@ custom_target('html_index.html',
   install_dir: tutorialdir
 )
 
+# Install extra files in the html directory.
+install_data('style.css', install_dir: tutorial_htmldir)
+install_data(tutorial_C_figures, install_dir: tutorial_figuresdir)
+install_data(tutorial_icons, install_dir: tutorial_iconsdir)
+
 if can_parse_and_validate
   # Parse and possibly validate the C locale's version of the DocBook.
   custom_target('C-xmllint',
@@ -219,21 +245,43 @@ if can_build_pdf
   )
 endif
 
-if can_build_translations and build_translations_by_default
-  # Build translations. Install help documentation using Yelp.
-  # C/index.docbook is copied from the source directory.
-  # <lang>/index.docbook are written to the build directory, and copied from there.
-  # It's bad that gnome.yelp() builds only at install time.
-  # See https://github.com/mesonbuild/meson/issues/2775
-  gnome.yelp('gtkmm-tutorial',
-    sources: 'index.docbook',
-    media: tutorial_figures,
-    symlink_media: true
-)
-endif
+# gnome.yelp() is not used. After issue https://github.com/mesonbuild/meson/issues/2775
+# was fixed in meson 0.61.0, gnome.yelp() can't be used on a generated XML file.
+# See https://github.com/mesonbuild/meson/issues/10017
 
-# Install extra files in the html directory.
-install_data('style.css', install_dir: tutorial_htmldir)
-install_data(tutorial_C_figures, install_dir: tutorial_figuresdir)
-install_data(tutorial_icons, install_dir: tutorial_iconsdir)
+foreach language : languages
+  # Create translated XML files.
+  translated_xml_target = custom_target(language + '_xml_index.docbook',
+    input: [language / language + '.po', index_docbook],
+    output: language + '_xml.stamp',
+    command: [
+      python3, tutorial_custom_cmd, 'translate_xml',
+      '@INPUT0@',
+      '@INPUT1@',
+      meson.current_build_dir() / language, # Absolute path
+      '@OUTPUT@',
+    ],
+    build_by_default: true,
+    install: false,
+  )
 
+  # Install the translated XML file.
+  # Install extra symlinks in the translated XML file directory.
+  tutorial_language_xmldir = install_datadir / 'help' / language / gtkmm_tutorial
+  meson.add_install_script(
+    python3, tutorial_custom_cmd, 'install',
+    meson.current_build_dir() / language,
+    tutorial_language_xmldir,
+    'index.docbook',
+    '..' / '..' / '..' / 'C' / gtkmm_tutorial / 'figures', # relative symlink dir
+    tutorial_figurefiles,
+  )
+  # Install extra symlinks in the translated XML file directory.
+  # install_symlink() requires meson >= 0.61.0
+  #foreach figure : tutorial_figurefiles
+  #  install_symlink(figure,
+  #    install_dir: tutorial_language_xmldir / 'figures',
+  #    pointing_to: '..' / '..' / '..' / 'C' / gtkmm_tutorial / 'figures' / figure,
+  #  )
+  #endforeach
+endforeach
diff --git a/tools/meson_aux/extra-dist-cmd.py b/tools/meson_aux/extra-dist-cmd.py
index 051c4e1..0bd1f09 100755
--- a/tools/meson_aux/extra-dist-cmd.py
+++ b/tools/meson_aux/extra-dist-cmd.py
@@ -11,7 +11,6 @@ import os
 import sys
 import shutil
 import subprocess
-import re
 
 root_source_dir = sys.argv[1]
 root_build_dir = sys.argv[2]
@@ -52,19 +51,18 @@ shutil.copytree(os.path.join('docs', 'tutorial', 'html'),
 # Read the distributed LINGUAS file, containing a list of available translations.
 linguas = os.path.join(dist_docs_tutorial, 'LINGUAS')
 langs = []
-if os.path.isfile(linguas):
-  with open(linguas, mode='r', encoding='utf-8') as linguas_file_obj:
-    buffer = linguas_file_obj.readlines()
-  comment_pattern = re.compile(r'\s*(?:#|$)') # comment or blank line
-  for line in buffer:
-    if not comment_pattern.match(line):
-      langs += line.split()
-else:
+try:
+  with open(linguas, encoding='utf-8') as f:
+    for line in f:
+      line = line.strip()
+      if line and not line.startswith('#'):
+        langs += line.split()
+except (FileNotFoundError, PermissionError):
   print('=== Warning: File', linguas, 'not found.')
 
-# .gmo files with translations and translated index.docbook files.
+# .mo files with translations and translated index.docbook files.
 for lang in langs:
-  for file in [lang + '.gmo', 'index.docbook']:
+  for file in [lang + '.mo', 'index.docbook']:
     shutil.copy(os.path.join('docs', 'tutorial', lang, file),
                 os.path.join(dist_docs_tutorial, lang))
 
diff --git a/tools/meson_aux/tutorial-custom-cmd.py b/tools/meson_aux/tutorial-custom-cmd.py
index 0cc6e73..a97c4c9 100755
--- a/tools/meson_aux/tutorial-custom-cmd.py
+++ b/tools/meson_aux/tutorial-custom-cmd.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# External command, intended to be called with custom_target() in meson.build
+# External command, intended to be called in meson.build
 
 #                           argv[1]   argv[2:]
 # tutorial-custom-cmd.py <subcommand> <xxx>...
@@ -9,9 +9,32 @@ import os
 import sys
 import subprocess
 import shutil
+from pathlib import Path
 
 subcommand = sys.argv[1]
 
+# Called from run_command()
+def get_languages():
+  #   argv[2]
+  # <input_dir>
+
+  input_dir = sys.argv[2]
+
+  # Syntax of the LINGUAS file is documented here:
+  # https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html
+  linguas_file = os.path.join(input_dir, 'LINGUAS')
+  try:
+    with open(linguas_file, encoding='utf-8') as f:
+      for line in f:
+        line = line.strip()
+        if line and not line.startswith('#'):
+          print(line, end=' ')
+  except (FileNotFoundError, PermissionError):
+    print('Could not find file LINGUAS in', input_dir, file=sys.stderr)
+    return 1
+  return 0
+
+# Called from custom_target()
 def insert_ex_code():
   #     argv[2]          argv[3]            argv[4]          argv[5]
   # <py_script_dir> <examples_book_dir> <input_xml_file> <output_xml_file>
@@ -24,14 +47,9 @@ def insert_ex_code():
   input_xml_file = sys.argv[4]
   output_xml_file = sys.argv[5]
 
-  returncode = insert_example_code(examples_book_dir, input_xml_file, output_xml_file)
-  if returncode:
-    return returncode
-
-  # Copy output_xml_file to the source directory.
-  shutil.copy(output_xml_file, os.path.dirname(input_xml_file))
-  return 0
+  return insert_example_code(examples_book_dir, input_xml_file, output_xml_file)
 
+# Called from custom_target()
 def html():
   #      argv[2]          argv[3]
   # <input_xml_file> <output_html_dir>
@@ -80,8 +98,8 @@ def html():
 
   return result.returncode
 
+# Called from custom_target()
 def xmllint():
-  from pathlib import Path
 
   #  argv[2]       argv[3]          argv[4]
   # <validate> <input_xml_file> <stamp_file_path>
@@ -118,9 +136,49 @@ def xmllint():
   Path(stamp_file_path).touch(exist_ok=True)
   return 0
 
+# Called from custom_target()
+def translate_xml():
+  #      argv[2]         argv[3]          argv[4]          argv[5]
+  # <input_po_file> <input_xml_file> <output_xml_dir> <stamp_file_path>
+
+  input_po_file = sys.argv[2]
+  input_xml_file = sys.argv[3]
+  output_xml_dir = sys.argv[4] # Absolute path
+  stamp_file_path = sys.argv[5]
+  input_xml_dir, input_xml_basename = os.path.split(input_xml_file)
+
+  # Create the destination directory, if it does not exist.
+  os.makedirs(output_xml_dir, exist_ok=True)
+
+  # Create an .mo file.
+  language = os.path.splitext(os.path.basename(input_po_file))[0]
+  mo_file = os.path.join(output_xml_dir, language + '.mo')
+  cmd = [
+    'msgfmt',
+    '-o', mo_file,
+    input_po_file,
+  ]
+  result = subprocess.run(cmd)
+  if result.returncode:
+    return result.returncode
+
+  # Create translated XML files.
+  cmd = [
+    'itstool',
+    '-m', mo_file,
+    '-o', output_xml_dir,
+  ] + [input_xml_basename]
+  result = subprocess.run(cmd, cwd=input_xml_dir)
+  if result.returncode:
+    return result.returncode
+
+  Path(stamp_file_path).touch(exist_ok=True)
+  return 0
+
 # dblatex and xsltproc+fop generate a PDF file.
 # docbook2pdf can generate PDF files from DocBook4 files, but not from DocBook5 files.
 # xsltproc+xmlroff (version 0.6.3) does not seem to work acceptably.
+# Called from custom_target()
 def dblatex():
   #      argv[2]        argv[3]        argv[4]
   # <input_xml_file> <figures_dir> <output_pdf_file>
@@ -149,6 +207,7 @@ def dblatex():
   ]
   return subprocess.run(cmd).returncode
 
+# Called from custom_target()
 def fop():
   #      argv[2]        argv[3]        argv[4]
   # <input_xml_file> <figures_dir> <output_pdf_file>
@@ -199,16 +258,57 @@ def fop():
   ]
   return subprocess.run(cmd).returncode
 
+# Called from meson.add_install_script()
+def install():
+  #      argv[2]           argv[3]              argv[4]         argv[5]       argv[6:]
+  # <input_xml_dir> <rel_install_xml_dir> <input_xml_file> <symlink_src_dir> <figures>...
+
+  # <rel_install_xml_dir> is the installation directory, relative to {prefix}.
+  input_xml_dir = sys.argv[2]
+  rel_install_xml_dir = sys.argv[3]
+  input_xml_file =  sys.argv[4]
+  symlink_src_dir = sys.argv[5]
+  figures = sys.argv[6:]
+  destdir_xmldir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), rel_install_xml_dir)
+  symlink_dest_dir = os.path.join(destdir_xmldir, 'figures')
+
+  # Create the installation directory, if it does not exist.
+  os.makedirs(symlink_dest_dir, exist_ok=True)
+
+  quiet = bool(os.getenv('MESON_INSTALL_QUIET'))
+  input_xml_path = os.path.join(input_xml_dir, input_xml_file)
+  if not quiet:
+    print('Installing ', input_xml_path, ' to ', destdir_xmldir)
+  # shutil.copy2() copies timestamps and some other file metadata.
+  shutil.copy2(input_xml_path, destdir_xmldir)
+
+  # Create symlinks from figure files in destdir_xmldir to the C locale's
+  # figure files.
+  if not quiet:
+    print('Installing symlinks pointing to ', symlink_src_dir, ' to ', symlink_dest_dir)
+  for f in figures:
+    symlink_dest_file = os.path.join(symlink_dest_dir, f)
+    if os.path.lexists(symlink_dest_file):
+      os.remove(symlink_dest_file)
+    os.symlink(os.path.join(symlink_src_dir, f), symlink_dest_file)
+  return 0
+
 # ----- Main -----
+if subcommand == 'get_languages':
+  sys.exit(get_languages())
 if subcommand == 'insert_example_code':
   sys.exit(insert_ex_code())
 if subcommand == 'html':
   sys.exit(html())
 if subcommand == 'xmllint':
   sys.exit(xmllint())
+if subcommand == 'translate_xml':
+  sys.exit(translate_xml())
 if subcommand == 'dblatex':
   sys.exit(dblatex())
 if subcommand == 'fop':
   sys.exit(fop())
+if subcommand == 'install':
+  sys.exit(install())
 print(sys.argv[0], ': illegal subcommand,', subcommand)
 sys.exit(1)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]