summaryrefslogtreecommitdiffstats
path: root/comm/python/thirdroc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/python/thirdroc
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/python/thirdroc')
-rw-r--r--comm/python/thirdroc/rnp_generated.py116
-rw-r--r--comm/python/thirdroc/setup.py24
-rw-r--r--comm/python/thirdroc/thirdroc/__init__.py0
-rw-r--r--comm/python/thirdroc/thirdroc/cmake_define_files.py102
-rw-r--r--comm/python/thirdroc/thirdroc/rnp_symbols.py131
5 files changed, 373 insertions, 0 deletions
diff --git a/comm/python/thirdroc/rnp_generated.py b/comm/python/thirdroc/rnp_generated.py
new file mode 100644
index 0000000000..9c3390e4b9
--- /dev/null
+++ b/comm/python/thirdroc/rnp_generated.py
@@ -0,0 +1,116 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import argparse
+import os
+import sys
+
+from packaging.version import parse
+
+from mozbuild.preprocessor import Preprocessor
+from mozbuild.util import FileAvoidWrite, ensureParentDir
+
+from thirdroc.cmake_define_files import define_type, process_cmake_define_file
+
+
+def rnp_version(version_file, thunderbird_version):
+ """
+ Update RNP source files: generate version.h
+ :param string version_file:
+ """
+ with open(version_file) as fp:
+ version_str = fp.readline(512).strip()
+
+ version = parse(version_str)
+ version_major = version.major
+ version_minor = version.minor
+ version_patch = version.micro
+
+ version_full = f"{version_str}.MZLA.{thunderbird_version}"
+
+ defines = dict(
+ RNP_VERSION_MAJOR=version_major,
+ RNP_VERSION_MINOR=version_minor,
+ RNP_VERSION_PATCH=version_patch,
+ RNP_VERSION=version_str,
+ RNP_VERSION_FULL=version_full,
+ # Follow upstream's example when commit info is unavailable
+ RNP_VERSION_COMMIT_TIMESTAMP="0",
+ PACKAGE_STRING=f'"rnp {version_full}"',
+ )
+
+ return defines
+
+
+def rnp_preprocess(tmpl, dest, defines):
+ """
+ Generic preprocessing
+ :param BinaryIO tmpl: open filehandle (read) input
+ :param BinaryIO dest: open filehandle (write) output
+ :param dict defines: result of get_defines()
+ :return boolean:
+ """
+ pp = Preprocessor()
+ pp.setMarker("%")
+ pp.addDefines(defines)
+ pp.do_filter("substitution")
+ pp.out = dest
+ pp.do_include(tmpl, True)
+ return True
+
+
+def generate_version_h(output, template, defines):
+ """
+ Generate version.h for rnp from a the template file, write the
+ result to destination.
+ :param string template: path to template file (version.h.in)
+ :param string destination: path to write generated file (version.h)
+ :param dict defines: result of get_defines()
+ """
+ with open(template) as tmpl:
+ rnp_preprocess(tmpl, output, defines)
+
+
+def main(output, *argv):
+ parser = argparse.ArgumentParser(description="Preprocess RNP files.")
+
+ parser.add_argument("version_h_in", help="version.h.in")
+ parser.add_argument("config_h_in", help="config.h.in")
+ parser.add_argument("-m", type=str, dest="thunderbird_version", help="Thunderbird version")
+ parser.add_argument("-V", type=str, dest="version_file", help="Path to RNP version.txt")
+ parser.add_argument(
+ "-D",
+ type=define_type,
+ action="append",
+ dest="extra_defines",
+ default=[],
+ help="Additional defines not set at configure time.",
+ )
+
+ args = parser.parse_args(argv)
+
+ defines = rnp_version(args.version_file, args.thunderbird_version)
+
+ # "output" is an open filedescriptor for version.h
+ generate_version_h(output, args.version_h_in, defines)
+
+ # We must create the remaining output files ourselves. This requires
+ # creating the output directory directly if it doesn't already exist.
+ ensureParentDir(output.name)
+ parent_dir = os.path.dirname(output.name)
+
+ # For config.h, include defines set for version.h and extra -D args
+ config_h_defines = dict(args.extra_defines)
+ config_h_defines.update(defines)
+
+ with FileAvoidWrite(os.path.join(parent_dir, "config.h")) as fd:
+ process_cmake_define_file(fd, args.config_h_in, config_h_defines)
+
+
+if __name__ == "__main__":
+ sys.exit(main(*sys.argv))
diff --git a/comm/python/thirdroc/setup.py b/comm/python/thirdroc/setup.py
new file mode 100644
index 0000000000..2a4cf6d3b5
--- /dev/null
+++ b/comm/python/thirdroc/setup.py
@@ -0,0 +1,24 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from setuptools import find_packages, setup
+
+VERSION = "0.1"
+
+setup(
+ author="MZLA Technologies",
+ author_email="MZLA Technologies Release Engineering",
+ name="thirdroc",
+ description="Utility for maintaining third party source code in Thunderbird",
+ license="MPL 2.0",
+ packages=find_packages(),
+ version=VERSION,
+ classifiers=[
+ "Development Status :: 3 - Alpha",
+ "Topic :: Software Development :: Build Tools",
+ "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: Implementation :: CPython",
+ ],
+)
diff --git a/comm/python/thirdroc/thirdroc/__init__.py b/comm/python/thirdroc/thirdroc/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/comm/python/thirdroc/thirdroc/__init__.py
diff --git a/comm/python/thirdroc/thirdroc/cmake_define_files.py b/comm/python/thirdroc/thirdroc/cmake_define_files.py
new file mode 100644
index 0000000000..2c53bf2d54
--- /dev/null
+++ b/comm/python/thirdroc/thirdroc/cmake_define_files.py
@@ -0,0 +1,102 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import argparse
+import os
+import re
+import sys
+
+from buildconfig import topobjdir
+from mozbuild.backend.configenvironment import PartialConfigEnvironment
+
+
+def define_type(string):
+ vals = string.split("=", 1)
+ if len(vals) == 1:
+ vals.append(1)
+ elif vals[1].isdecimal():
+ vals[1] = int(vals[1])
+ return tuple(vals)
+
+
+def process_cmake_define_file(output, input_file, extra_defines):
+ """Creates the given config header. A config header is generated by
+ taking the corresponding source file and replacing some #define/#undef
+ occurrences:
+ "#undef NAME" is turned into "#define NAME VALUE"
+ "#cmakedefine NAME" is turned into "#define NAME VALUE"
+ "#define NAME" is unchanged
+ "#define NAME ORIGINAL_VALUE" is turned into "#define NAME VALUE"
+ "#undef UNKNOWN_NAME" is turned into "/* #undef UNKNOWN_NAME */"
+ "#cmakedefine UNKNOWN_NAME" is turned into "/* #undef UNKNOWN_NAME */"
+ Whitespaces are preserved.
+ """
+
+ path = os.path.abspath(input_file)
+
+ config = PartialConfigEnvironment(topobjdir)
+
+ defines = dict(config.defines.iteritems())
+ defines.update(extra_defines)
+
+ with open(path, "r") as input_file:
+ r = re.compile(
+ r'^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>("[^"]+"|\S+)))?)?',
+ re.U,
+ )
+ for line in input_file:
+ m = r.match(line)
+ if m:
+ cmd = m.group("cmd")
+ name = m.group("name")
+ value = m.group("value")
+ if name:
+ if cmd == "define":
+ if value and name in defines:
+ line = (
+ line[: m.start("value")]
+ + str(defines[name])
+ + line[m.end("value") :]
+ )
+ elif cmd in ("undef", "cmakedefine"):
+ if name in defines:
+ line = (
+ line[: m.start("cmd")]
+ + "define"
+ + line[m.end("cmd") : m.end("name")]
+ + " "
+ + str(defines[name])
+ + line[m.end("name") :]
+ )
+ else:
+ line = (
+ "/* #undef "
+ + line[m.start("name") : m.end("name")]
+ + " */"
+ + line[m.end("name") :]
+ )
+
+ output.write(line)
+
+
+def main(output, *argv):
+ parser = argparse.ArgumentParser(description="Process define files.")
+
+ parser.add_argument("input", help="Input define file.")
+ parser.add_argument(
+ "-D",
+ type=define_type,
+ action="append",
+ dest="extra_defines",
+ default=[],
+ help="Additional defines not set at configure time.",
+ )
+
+ args = parser.parse_args(argv)
+
+ return process_cmake_define_file(output, args.input, args.extra_defines)
+
+
+if __name__ == "__main__":
+ sys.exit(main(*sys.argv))
diff --git a/comm/python/thirdroc/thirdroc/rnp_symbols.py b/comm/python/thirdroc/thirdroc/rnp_symbols.py
new file mode 100644
index 0000000000..95f430f59c
--- /dev/null
+++ b/comm/python/thirdroc/thirdroc/rnp_symbols.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python3
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"""
+Parse rnp/rnp.h header file and build a symbols file suitable
+for use with mozbuild.
+
+This script is meant to be run when the public C API of librnp adds or removes functions so that
+they can be exported by the shared library.
+
+Limitations: The regex that captures the function name is very basic and may need adjusting if
+the third_party/rnp/include/rnp/rnp.h format changes too much.
+Also note that APIs that are marked deprecated are not checked for.
+
+Dependencies: Only Python 3
+
+Running:
+ python3 rnp_symbols.py [-h] [rnp.h path] [rnp.symbols path]
+
+Both file path arguments are optional. By default, the header file will be
+read from "comm/third_party/rnp/include/rnp/rnp.h" and the symbols file will
+be written to "comm/third_party/rnp/rnp.symbols".
+
+Path arguments are relative to the current working directory, the defaults
+will be determined based on the location of this script.
+
+Either path argument can be '-' to use stdin or stdout respectively.
+"""
+
+import argparse
+import os
+import re
+import sys
+
+HERE = os.path.dirname(__file__)
+TOPSRCDIR = os.path.abspath(os.path.join(HERE, "../../../../"))
+THIRD_SRCDIR = os.path.join(TOPSRCDIR, "comm/third_party")
+HEADER_FILE_REL = "rnp/include/rnp/rnp.h"
+HEADER_FILE = os.path.join(THIRD_SRCDIR, HEADER_FILE_REL)
+SYMBOLS_FILE_REL = "rnp/rnp.symbols"
+SYMBOLS_FILE = os.path.join(THIRD_SRCDIR, SYMBOLS_FILE_REL)
+
+
+FUNC_DECL_RE = re.compile(r"^RNP_API\s+.*?([a-zA-Z0-9_]+)\(.*$")
+
+
+class FileArg:
+ """Based on argparse.FileType from the Python standard library.
+ Modified to not open the filehandles until the open() method is
+ called.
+ """
+
+ def __init__(self, mode="r"):
+ self._mode = mode
+ self._fp = None
+ self._file = None
+
+ def __call__(self, string):
+ # the special argument "-" means sys.std{in,out}
+ if string == "-":
+ if "r" in self._mode:
+ self._fp = sys.stdin.buffer if "b" in self._mode else sys.stdin
+ elif "w" in self._mode:
+ self._fp = sys.stdout.buffer if "b" in self._mode else sys.stdout
+ else:
+ raise ValueError(f"Invalid mode {self._mode} for stdin/stdout")
+ else:
+ if "r" in self._mode:
+ if not os.path.isfile(string):
+ raise ValueError(f"Cannot read file {string}, does not exist.")
+ elif "w" in self._mode:
+ if not os.access(string, os.W_OK):
+ raise ValueError(f"Cannot write file {string}, permission denied.")
+ self._file = string
+ return self
+
+ def open(self):
+ if self._fp:
+ return self._fp
+ return open(self._file, self._mode)
+
+
+def get_func_name(line):
+ """
+ Extract the function name from a RNP_API function declaration.
+ Examples:
+ RNP_API rnp_result_t rnp_enable_debug(const char *file);
+
+ RNP_API rnp_result_t rnp_ffi_create(rnp_ffi_t * ffi,
+ """
+ m = FUNC_DECL_RE.match(line)
+ return m.group(1)
+
+
+def extract_func_defs(filearg):
+ """
+ Look for RNP_API in the header file to find the names of the symbols that should be exported
+ """
+ with filearg.open() as fp:
+ for line in fp:
+ if line.startswith("RNP_API") and "RNP_DEPRECATED" not in line:
+ func_name = get_func_name(line)
+ yield func_name
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Update rnp.symbols file from rnp.h",
+ epilog="To use stdin or stdout pass '-' for the argument.",
+ )
+ parser.add_argument(
+ "header_file",
+ default=HEADER_FILE,
+ type=FileArg("r"),
+ nargs="?",
+ help=f"input path to rnp.h header file (default: {HEADER_FILE_REL})",
+ )
+ parser.add_argument(
+ "symbols_file",
+ default=SYMBOLS_FILE,
+ type=FileArg("w"),
+ nargs="?",
+ help=f"output path to symbols file (default: {SYMBOLS_FILE_REL})",
+ )
+
+ args = parser.parse_args()
+
+ with args.symbols_file.open() as out_fp:
+ for symbol in sorted(list(extract_func_defs(args.header_file))):
+ out_fp.write(f"{symbol}\n")