1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5from __future__ import absolute_import
6
7import os
8from io import StringIO
9from datetime import date
10import re
11from distutils.version import StrictVersion
12
13from mozbuild.preprocessor import Preprocessor
14
15
16def rnp_source_update(rnp_root, version_str, revision, timestamp, bug_report):
17    """
18    Update RNP source files: generate version.h and mangle config.h.in
19    :param rnp_root:
20    :type rnp_root:
21    :param string version_str: latest version
22    :param string revision: revision hash (short form)
23    :param float timestamp: UNIX timestamp from revision
24    :param string bug_report: where to report bugs for this RNP build
25    """
26    version = StrictVersion(version_str)
27    version_major = version.version[0]
28    version_minor = version.version[1]
29    version_patch = version.version[2]
30    date_str = date.fromtimestamp(float(timestamp)).strftime("%Y%m%d")
31    revision_short = revision[:8]
32    version_full = "{}+git{}.{}.MZLA".format(version_str, date_str, revision_short)
33
34    defines = dict(
35        RNP_VERSION_MAJOR=version_major,
36        RNP_VERSION_MINOR=version_minor,
37        RNP_VERSION_PATCH=version_patch,
38        RNP_VERSION=version_str,
39        RNP_VERSION_FULL=version_full,
40        RNP_VERSION_COMMIT_TIMESTAMP=str(timestamp),
41        BUGREPORT_EMAIL=bug_report,
42    )
43    src_lib = os.path.join(rnp_root, "src", "lib")
44    version_h_in = os.path.join(src_lib, "version.h.in")
45    version_h = os.path.join(src_lib, "version.h")
46    config_h_in = os.path.join(src_lib, "config.h.in")
47    readme_rnp = os.path.join(rnp_root, "..", "README.rnp")
48
49    generate_version_h(version_h_in, version_h, defines)
50    mangle_config_h_in(config_h_in, defines)
51    update_readme(readme_rnp, revision)
52
53
54def rnp_preprocess(tmpl, dest, defines):
55    """
56    Generic preprocessing
57    :param BinaryIO tmpl: open filehandle (read) input
58    :param BinaryIO dest: open filehandle (write) output
59    :param dict defines: result of get_defines()
60    :return boolean:
61    """
62    pp = Preprocessor()
63    pp.setMarker("%")
64    pp.addDefines(defines)
65    pp.do_filter("substitution")
66    pp.out = dest
67    pp.do_include(tmpl, True)
68    return True
69
70
71def generate_version_h(template, destination, defines):
72    """
73    Generate version.h for rnp from a the template file, write the
74    result to destination.
75    :param string template: path to template file (version.h.in)
76    :param string destination: path to write generated file (version.h)
77    :param dict defines: result of get_defines()
78    """
79    with open(template) as tmpl:
80        with open(destination, "w") as dest:
81            rnp_preprocess(tmpl, dest, defines)
82
83
84def mangle_config_h_in(template, defines):
85    """
86    Mangle RNP's config.h.in so that it will work with CONFIGURE_DEFINE_FILES
87    :param string template: path to config.h.in
88    :param dict defines: result of get_defines()
89    """
90    with open(template) as tmpl:
91        tmp_string = StringIO()
92        rnp_preprocess(tmpl, tmp_string, defines)
93
94    tmp_string.seek(0)
95
96    with open(template, "w") as dest:
97        for line in tmp_string:
98            if line.startswith("#cmakedefine"):
99                line = line.replace("#cmakedefine", "#undef")
100            dest.write(line)
101        dest.write("\n")
102
103
104def update_readme(path, revision):
105    """
106    Updates the commit hash in README.rnp
107    :param string path: Path to README.rnp
108    :param string revision: revision to insert
109    """
110    commit_re = re.compile(r"^\[commit [\da-f]{40}\]$")
111    with open(path) as orig:
112        tmp_string = StringIO()
113        tmp_string.write(orig.read())
114
115    tmp_string.seek(0)
116
117    with open(path, "w") as dest:
118        for line in tmp_string:
119            if commit_re.match(line):
120                line = "[commit {}]\n".format(revision)
121            dest.write(line)
122