diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/python/thirdroc | |
parent | Initial commit. (diff) | |
download | thunderbird-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.py | 116 | ||||
-rw-r--r-- | comm/python/thirdroc/setup.py | 24 | ||||
-rw-r--r-- | comm/python/thirdroc/thirdroc/__init__.py | 0 | ||||
-rw-r--r-- | comm/python/thirdroc/thirdroc/cmake_define_files.py | 102 | ||||
-rw-r--r-- | comm/python/thirdroc/thirdroc/rnp_symbols.py | 131 |
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") |