[gnomemm-website] Add Meson support
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnomemm-website] Add Meson support
- Date: Fri, 14 Jan 2022 15:28:49 +0000 (UTC)
commit 20197989c2b4d6ea533a0b1adc8875f1c673bced
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date: Fri Jan 14 16:23:12 2022 +0100
Add Meson support
The website can be built with Meson or Autotools.
Makefile.am | 9 ++
docs/LINGUAS | 13 +++
docs/meson.build | 139 +++++++++++++++++++++++++++
meson.build | 87 +++++++++++++++++
meson_options.txt | 4 +
tools/extra-dist-cmd.py | 95 +++++++++++++++++++
tools/website-custom-cmd.py | 225 ++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 572 insertions(+)
---
diff --git a/Makefile.am b/Makefile.am
index 9b82b26..392d43e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,3 +4,12 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-warnings=fatal
SUBDIRS = docs
dist_noinst_SCRIPTS = autogen.sh
+
+# Distribute files needed when building with Meson.
+EXTRA_DIST = \
+ meson.build \
+ meson_options.txt \
+ docs/meson.build \
+ docs/LINGUAS \
+ tools/extra-dist-cmd.py \
+ tools/website-custom-cmd.py
diff --git a/docs/LINGUAS b/docs/LINGUAS
new file mode 100644
index 0000000..ed421c1
--- /dev/null
+++ b/docs/LINGUAS
@@ -0,0 +1,13 @@
+# Please keep this list sorted alphabetically.
+#
+cs
+de
+el
+es
+fr
+hu
+ko
+pt_BR
+sl
+sv
+zh_CN
diff --git a/docs/meson.build b/docs/meson.build
new file mode 100644
index 0000000..edc694c
--- /dev/null
+++ b/docs/meson.build
@@ -0,0 +1,139 @@
+# docs
+
+# input: install_datadir, website_custom_cmd, python3
+# output: can_parse_and_validate, build_translations_by_default, can_build_translations
+
+# xsltproc is required by website_custom_cmd html.
+xsltproc = find_program('xsltproc', required: true)
+
+xmllint = find_program('xmllint', required: false)
+can_parse_and_validate = xmllint.found()
+validate = get_option('validation') ? 'true' : 'false'
+
+can_build_translations = find_program('msgfmt', required: false).found() and \
+ find_program('itstool', required: false).found()
+build_translations_by_default = get_option('build-translations')
+
+xml_files = [
+ 'index.docbook', # Must be the first element in the list
+ 'books.xml',
+ 'bugs.xml',
+ 'commercial_support.xml',
+ 'developers.xml',
+ 'documentation.xml',
+ 'download.xml',
+ 'extra.xml',
+ 'git.xml',
+ 'license.xml',
+ 'mailinglist.xml',
+ 'main.xml',
+ 'news.xml',
+]
+xml_C_files = []
+foreach f : xml_files
+ xml_C_files += 'C' / f
+endforeach
+
+if can_build_translations and build_translations_by_default
+ # Get a list of translated languages.
+ language_obj = run_command(
+ python3, website_custom_cmd, 'get_languages',
+ meson.current_source_dir(),
+ )
+ if language_obj.stderr() != ''
+ warning(language_obj.stderr())
+ endif
+ languages = language_obj.stdout().split()
+else
+ languages = []
+endif
+
+if can_parse_and_validate
+ # Parse and possibly validate the C locale's version of the DocBook.
+ custom_target('C-xmllint',
+ input: xml_C_files,
+ output: 'C_xmllint.stamp',
+ command: [
+ python3, website_custom_cmd, 'xmllint',
+ validate,
+ '@INPUT0@',
+ '@OUTPUT@'
+ ],
+ build_by_default: true,
+ )
+endif
+
+stylesheet_file = meson.current_source_dir() / 'param.xsl'
+
+publishing_targets = []
+
+# Create an html version of the C locale's version of the DocBook.
+publishing_targets += custom_target('en_html_index.html',
+ input: [stylesheet_file] + xml_C_files,
+ output: 'en_html.stamp',
+ command: [
+ python3, website_custom_cmd, 'html',
+ '@INPUT0@',
+ '@INPUT1@',
+ meson.current_build_dir() / 'html' / 'en',
+ '@OUTPUT@',
+ ],
+ build_by_default: true,
+ install: false,
+)
+
+# Install the C locale's XML files.
+install_data(xml_C_files, install_dir: install_datadir / 'help' / 'C' / meson.project_name())
+
+# gnome.yelp() is not used. It builds translations only at install time.
+# This project is not necessarily installed before it's published at www.gtkmm.org.
+# See https://github.com/mesonbuild/meson/issues/2775
+
+foreach language : languages
+ # Create translated XML files.
+ tanslated_xml_target = custom_target(language + '_xml_index.docbook',
+ input: [language / language + '.po'] + xml_C_files,
+ output: language + '_xml.stamp',
+ command: [
+ python3, website_custom_cmd, 'translate_xml',
+ '@INPUT0@',
+ meson.current_source_dir() / 'C',
+ meson.current_build_dir() / language, # Absolute path
+ '@OUTPUT@',
+ xml_files,
+ ],
+ build_by_default: true,
+ install: false,
+ )
+
+ # Create an html version of the translated version of the DocBook.
+ publishing_targets += custom_target(language + '_html_index.html',
+ input: [stylesheet_file, tanslated_xml_target],
+ output: language + '_html.stamp',
+ command: [
+ python3, website_custom_cmd, 'html',
+ '@INPUT0@',
+ meson.current_build_dir() / language / xml_files[0],
+ meson.current_build_dir() / 'html' / language,
+ '@OUTPUT@',
+ ],
+ build_by_default: true,
+ install: false,
+ )
+
+ # Install the translated XML files.
+ meson.add_install_script(
+ python3, website_custom_cmd, 'install',
+ meson.current_build_dir() / language,
+ install_datadir / 'help' / language / meson.project_name(),
+ xml_files,
+ )
+endforeach
+
+# Publish the website at www.gtkmm.org.
+run_target('publish',
+ command: [
+ python3, website_custom_cmd, 'publish',
+ ],
+ depends: publishing_targets,
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..65f612d
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,87 @@
+# This file is part of gnomemm-website.
+
+project('gnomemm-website',
+ version: '2.91.4',
+ meson_version: '>= 0.50.0', # required for python3.path()
+)
+
+python3 = import('python').find_installation()
+python_version = python3.language_version()
+python_version_req = '>= 3.5'
+if not python_version.version_compare(python_version_req)
+ error('Requires Python @0@, found @1@.'.format(python_version_req, python_version))
+endif
+
+# Installation directories are relative to {prefix}.
+install_prefix = get_option('prefix')
+install_datadir = get_option('datadir')
+
+# Use these instead of meson.source_root() and meson.build_root() in subdirectories.
+# source_root() and build_root() are not useful, if this is a subproject.
+project_source_root = meson.current_source_dir()
+project_build_root = meson.current_build_dir()
+
+script_dir = project_source_root / 'tools'
+website_custom_cmd = script_dir / 'website-custom-cmd.py'
+extra_dist_cmd = script_dir / 'extra-dist-cmd.py'
+
+# Copy some files to the build directory.
+copy_obj = run_command(
+ python3, website_custom_cmd, 'copy_files_and_dirs',
+ project_source_root / 'docs' / 'html',
+ project_build_root / 'docs' / 'html',
+ 'index.html',
+ '.htaccess',
+ 'images',
+ 'style',
+)
+if copy_obj.stdout() != ''
+ warning(copy_obj.stdout())
+endif
+
+# add_dist_script() is not allowed in a subproject if meson.version() < 0.58.0.
+can_add_dist_script = not meson.is_subproject() or meson.version().version_compare('>= 0.58.0')
+
+subdir('docs')
+
+if can_add_dist_script
+ # Don't distribute these files and directories.
+ dont_distribute = [
+ '.gitlab-ci.yml',
+ ]
+ # Modify the contents of the distribution directory.
+ meson.add_dist_script(
+ python3.path(), extra_dist_cmd,
+ project_source_root,
+ project_build_root,
+ dont_distribute,
+ )
+endif
+
+# Print a summary.
+validate = get_option('validation') and can_parse_and_validate
+explain_val = ''
+if get_option('validation') and not validate
+ explain_val = ' (requires xmllint)'
+endif
+
+build_translations = build_translations_by_default and can_build_translations
+explain_trans = ''
+if build_translations_by_default and not build_translations
+ explain_trans = ' (requires msgfmt and itstool)'
+endif
+
+summary = [
+ '',
+ '------',
+ meson.project_name() + ' ' + meson.project_version(),
+ '',
+ ' XML validation: @0@@1@'.format(validate, explain_val),
+ 'Build translations: @0@@1@'.format(build_translations, explain_trans),
+ 'Directories:',
+ ' prefix: @0@'.format(install_prefix),
+ ' datadir: @0@'.format(install_prefix / install_datadir),
+ '------'
+]
+
+message('\n'.join(summary))
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..34a224e
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,4 @@
+option('validation', type: 'boolean', value: false,
+ description: 'Validate the untranslated XML file')
+option('build-translations', type: 'boolean', value: true,
+ description: 'Build translated website')
diff --git a/tools/extra-dist-cmd.py b/tools/extra-dist-cmd.py
new file mode 100755
index 0000000..c9c59b0
--- /dev/null
+++ b/tools/extra-dist-cmd.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with meson.add_dist_script() in meson.build
+
+# argv[1] argv[2] argv[3:]
+# extra-dist-cmd.py <root_source_dir> <root_build_dir> <no_dist>...
+
+# Meson does not preserve timestamps on distributed files. Neither does this script.
+
+import os
+import sys
+import shutil
+import subprocess
+import glob
+
+root_source_dir = sys.argv[1]
+root_build_dir = sys.argv[2]
+
+# MESON_PROJECT_DIST_ROOT is set only if meson.version() >= 0.58.0.
+project_dist_root = os.getenv('MESON_PROJECT_DIST_ROOT', os.getenv('MESON_DIST_ROOT'))
+
+# Make a ChangeLog file for distribution.
+cmd = [
+ 'git',
+ '--git-dir=' + os.path.join(root_source_dir, '.git'),
+ '--work-tree=' + root_source_dir,
+ 'log',
+ '--no-merges',
+ '--date=short',
+ '--max-count=200',
+ '--pretty=tformat:%cd %an <%ae>%n%n %s%n%w(0,0,2)%+b',
+]
+logfilename = os.path.join(project_dist_root, 'ChangeLog')
+with open(logfilename, mode='w', encoding='utf-8') as logfile:
+ result = subprocess.run(cmd, stdout=logfile)
+ if result.returncode:
+ sys.exit(result.returncode)
+
+# Distribute some built files in addition to the files in the local git clone.
+os.chdir(root_build_dir)
+dist_docs = os.path.join(project_dist_root, 'docs')
+
+# English html files.
+# shutil.copy() does not copy timestamps.
+shutil.copytree(os.path.join('docs', 'html', 'en'),
+ os.path.join(dist_docs, 'html', 'en'),
+ copy_function=shutil.copy)
+
+# Read the distributed LINGUAS file, containing a list of available translations.
+linguas = os.path.join(dist_docs, 'LINGUAS')
+langs = []
+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.')
+
+# .mo files with translations and translated XML files and html files.
+for lang in langs:
+ dist_docs_lang = os.path.join(dist_docs, lang)
+ for file in [lang + '.mo', 'index.docbook']:
+ shutil.copy(os.path.join('docs', lang, file), dist_docs_lang)
+ for file in glob.glob(os.path.join('docs', lang, '*.xml')):
+ shutil.copy(file, dist_docs_lang)
+ shutil.copytree(os.path.join('docs', 'html', lang),
+ os.path.join(dist_docs, 'html', lang),
+ copy_function=shutil.copy)
+
+# Don't distribute .gitignore files.
+for dirpath, dirnames, filenames in os.walk(project_dist_root):
+ if '.gitignore' in filenames:
+ os.remove(os.path.join(dirpath, '.gitignore'))
+
+# Remove an empty MESON_PROJECT_DIST_ROOT/build directory.
+dist_build_dir = os.path.join(project_dist_root, 'build')
+if os.path.isdir(dist_build_dir):
+ try:
+ os.rmdir(dist_build_dir)
+ except OSError:
+ # Ignore the error, if not empty.
+ pass
+
+# Remove specified files and directories from the MESON_PROJECT_DIST_ROOT directory.
+for rel_path in sys.argv[3:]:
+ abs_path = os.path.join(project_dist_root, rel_path)
+ if os.path.isfile(abs_path):
+ os.remove(abs_path)
+ elif os.path.isdir(abs_path):
+ shutil.rmtree(abs_path, ignore_errors=True)
+ else:
+ # Ignore non-existent files and directories.
+ print('--- Info:', abs_path, 'not found, not removed.')
diff --git a/tools/website-custom-cmd.py b/tools/website-custom-cmd.py
new file mode 100755
index 0000000..2be8dcd
--- /dev/null
+++ b/tools/website-custom-cmd.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called in meson.build
+
+# argv[1] argv[2:]
+# tutorial-custom-cmd.py <subcommand> <xxx>...
+
+import os
+import sys
+import subprocess
+import shutil
+from pathlib import Path
+
+subcommand = sys.argv[1]
+
+# Called from run_command()
+def copy_files_and_dirs():
+ # argv[2] argv[3] argv[4:]
+ # <input_dir> <output_dir> <files_and_dirs>...
+
+ input_dir = sys.argv[2]
+ output_dir = sys.argv[3]
+ files_and_dirs = sys.argv[4:]
+
+ for f in files_and_dirs:
+ input_path = os.path.join(input_dir, f)
+ output_path = os.path.join(output_dir, f)
+ if os.path.isfile(input_path):
+ # Create the destination directory, if it does not exist.
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
+ # shutil.copy2() copies timestamps and some other file metadata.
+ shutil.copy2(input_path, output_path)
+ elif os.path.isdir(input_path):
+ # Create the destination directory, if it does not exist.
+ os.makedirs(output_path, exist_ok=True)
+ shutil.copytree(input_path, output_path,
+ copy_function=shutil.copy2, dirs_exist_ok=True)
+ else:
+ # Ignore non-existent files and directories.
+ print(input_path, 'not found, not copied.')
+ return 0
+
+# 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)
+
+# Called from custom_target()
+def xmllint():
+ # argv[2] argv[3] argv[4]
+ # <validate> <input_xml_file> <stamp_file_path>
+
+ validate = sys.argv[2]
+ input_xml_file = sys.argv[3]
+ stamp_file_path = sys.argv[4]
+
+ cmd = [
+ 'xmllint',
+ '--noout',
+ '--noent',
+ '--xinclude',
+ ]
+ if validate == 'true':
+ cmd += ['--postvalid']
+ cmd += [input_xml_file]
+ result = subprocess.run(cmd)
+ if result.returncode:
+ return result.returncode
+
+ 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] argv[6:]
+ # <input_po_file> <input_xml_dir> <output_xml_dir> <stamp_file_path> <input_xml_files>...
+
+ input_po_file = sys.argv[2]
+ input_xml_dir = sys.argv[3]
+ output_xml_dir = sys.argv[4] # Absolute path
+ stamp_file_path = sys.argv[5]
+ input_xml_files = sys.argv[6:]
+
+ # 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_files
+ result = subprocess.run(cmd, cwd=input_xml_dir)
+ if result.returncode:
+ return result.returncode
+
+ Path(stamp_file_path).touch(exist_ok=True)
+ return 0
+
+# Called from custom_target()
+def html():
+ # argv[2] argv[3] argv[4] argv[5]
+ # <stylesheet_file> <input_xml_file> <output_html_dir> <stamp_file_path>
+
+ stylesheet_file = sys.argv[2]
+ input_xml_file = sys.argv[3]
+ output_html_dir = sys.argv[4]
+ stamp_file_path = sys.argv[5]
+
+ # Remove old files and create the destination directory.
+ shutil.rmtree(output_html_dir, ignore_errors=True)
+ os.makedirs(output_html_dir, exist_ok=True)
+
+ cmd = [
+ 'xsltproc',
+ '-o', output_html_dir + '/',
+ '--xinclude',
+ stylesheet_file,
+ input_xml_file,
+ ]
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ universal_newlines=True)
+ # xsltproc prints the names of all written files. Don't print those lines.
+ for line in result.stdout.splitlines():
+ if not line.startswith('Writing '):
+ print(line)
+
+ if result.returncode:
+ return result.returncode
+
+ # Remove root.html.
+ root_html_file = os.path.join(output_html_dir, 'root.html')
+ if os.path.isfile(root_html_file):
+ os.remove(root_html_file)
+
+ Path(stamp_file_path).touch(exist_ok=True)
+ return 0
+
+# Called from meson.add_install_script()
+def install():
+ # argv[2] argv[3] argv[4:]
+ # <input_xml_dir> <rel_install_xml_dir> <input_xml_files>...
+
+ # <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_files = sys.argv[4:]
+ destdir_xmldir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), rel_install_xml_dir)
+
+ # Create the installation directory, if it does not exist.
+ os.makedirs(destdir_xmldir, exist_ok=True)
+
+ for f in input_xml_files:
+ # shutil.copy2() copies timestamps and some other file metadata.
+ shutil.copy2(os.path.join(input_xml_dir, f), destdir_xmldir)
+ return 0
+
+# Called from run_target()
+def publish():
+ import glob
+
+ # Use environment variable GTKMM_WEB_USER if it exists, else USER
+ user_name = os.getenv('GTKMM_WEB_USER', os.getenv('USER'))
+
+ os.chdir(os.path.join(os.getenv('MESON_BUILD_ROOT'), 'docs'))
+ html_dirs = glob.glob(os.path.join('html', '*'))
+ web_path = '/home/murrayc/gtkmm.org/'
+
+ # rsync -avz --rsh ssh --cvs-exclude html/.htaccess html/* $$USER www gtkmm org:$(web_path)
+ cmd = [
+ 'rsync',
+ '-avz', '--rsh', 'ssh', '--cvs-exclude',
+ 'html/.htaccess',
+ ] + html_dirs + [
+ user_name + '@www.gtkmm.org:' + web_path,
+ ]
+ #return subprocess.run(cmd).returncode
+ print('The "publish" target is disabled.')
+ print('To enable it, edit', sys.argv[0])
+ print(' '.join(cmd))
+ return 0
+
+# ----- Main -----
+if subcommand == 'copy_files_and_dirs':
+ sys.exit(copy_files_and_dirs())
+if subcommand == 'get_languages':
+ sys.exit(get_languages())
+if subcommand == 'xmllint':
+ sys.exit(xmllint())
+if subcommand == 'translate_xml':
+ sys.exit(translate_xml())
+if subcommand == 'html':
+ sys.exit(html())
+if subcommand == 'install':
+ sys.exit(install())
+if subcommand == 'publish':
+ sys.exit(publish())
+print(sys.argv[0], ': illegal subcommand,', subcommand)
+sys.exit(1)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]