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 datetime import datetime 6import io 7import os 8import sys 9 10from mozbuild.preprocessor import Preprocessor 11import buildconfig 12 13 14TEMPLATE = """ 15// This Source Code Form is subject to the terms of the Mozilla Public 16// License, v. 2.0. If a copy of the MPL was not distributed with this 17// file, You can obtain one at http://mozilla.org/MPL/2.0/. 18 19#include<winuser.h> 20#include<winver.h> 21 22// Note: if you contain versioning information in an included 23// RC script, it will be discarded 24// Use module.ver to explicitly set these values 25 26// Do not edit this file. Changes won't affect the build. 27 28{include} 29 30 31///////////////////////////////////////////////////////////////////////////// 32// 33// Version 34// 35 361 VERSIONINFO 37 FILEVERSION {fileversion} 38 PRODUCTVERSION {productversion} 39 FILEFLAGSMASK 0x3fL 40 FILEFLAGS {fileflags} 41 FILEOS VOS__WINDOWS32 42 FILETYPE VFT_DLL 43 FILESUBTYPE 0x0L 44BEGIN 45 BLOCK "StringFileInfo" 46 BEGIN 47 BLOCK "000004b0" 48 BEGIN 49 VALUE "Comments", "{comment}" 50 VALUE "LegalCopyright", "{copyright}" 51 VALUE "CompanyName", "{company}" 52 VALUE "FileDescription", "{description}" 53 VALUE "FileVersion", "{mfversion}" 54 VALUE "ProductVersion", "{mpversion}" 55 VALUE "InternalName", "{module}" 56 VALUE "LegalTrademarks", "{trademarks}" 57 VALUE "OriginalFilename", "{binary}" 58 VALUE "ProductName", "{productname}" 59 VALUE "BuildID", "{buildid}" 60 END 61 END 62 BLOCK "VarFileInfo" 63 BEGIN 64 VALUE "Translation", 0x0, 1200 65 END 66END 67 68""" 69 70 71def preprocess(path, defines): 72 pp = Preprocessor(defines=defines, marker="%") 73 pp.context.update(defines) 74 pp.out = io.StringIO() 75 pp.do_filter("substitution") 76 pp.do_include(io.open(path, "r", encoding="latin1")) 77 pp.out.seek(0) 78 return pp.out 79 80 81def parse_module_ver(path, defines): 82 result = {} 83 for line in preprocess(path, defines): 84 content, *comment = line.split("#", 1) 85 if not content.strip(): 86 continue 87 entry, value = content.split("=", 1) 88 result[entry.strip()] = value.strip() 89 return result 90 91 92def get_buildid(): 93 path = os.path.join(buildconfig.topobjdir, "buildid.h") 94 define, MOZ_BUILDID, buildid = io.open(path, "r", encoding="utf-8").read().split() 95 return buildid 96 97 98def days_from_2000_to_buildid(buildid): 99 start = datetime(2000, 1, 1, 0, 0, 0) 100 buildid_time = datetime.strptime(buildid, "%Y%m%d%H%M%S") 101 return (buildid_time - start).days 102 103 104def digits_only(s): 105 for l in range(len(s), 0, -1): 106 if s[:l].isdigit(): 107 return s[:l] 108 return "0" 109 110 111def split_and_normalize_version(version, len): 112 return ([digits_only(x) for x in version.split(".")] + ["0"] * len)[:len] 113 114 115def has_manifest(module_rc, manifest_id): 116 for line in module_rc.splitlines(): 117 line = line.split(None, 2) 118 if len(line) < 2: 119 continue 120 id, what, *rest = line 121 if id == manifest_id and what in ("24", "RT_MANIFEST"): 122 return True 123 return False 124 125 126def generate_module_rc(binary="", rcinclude=None): 127 deps = set() 128 buildid = get_buildid() 129 milestone = buildconfig.substs["GRE_MILESTONE"] 130 app_version = buildconfig.substs.get("MOZ_APP_VERSION") or milestone 131 app_winversion = ",".join(split_and_normalize_version(app_version, 4)) 132 milestone_winversion = ",".join( 133 split_and_normalize_version(milestone, 3) 134 + [str(days_from_2000_to_buildid(buildid))] 135 ) 136 display_name = buildconfig.substs.get("MOZ_APP_DISPLAYNAME", "Mozilla") 137 138 milestone_string = milestone 139 140 flags = ["0"] 141 if buildconfig.substs.get("MOZ_DEBUG"): 142 flags.append("VS_FF_DEBUG") 143 milestone_string += " Debug" 144 if not buildconfig.substs.get("MOZILLA_OFFICIAL"): 145 flags.append("VS_FF_PRIVATEBUILD") 146 if buildconfig.substs.get("NIGHTLY_BUILD"): 147 flags.append("VS_FF_PRERELEASE") 148 149 defines = { 150 "MOZ_APP_DISPLAYNAME": display_name, 151 "MOZ_APP_VERSION": app_version, 152 "MOZ_APP_WINVERSION": app_winversion, 153 } 154 155 relobjdir = os.path.relpath(".", buildconfig.topobjdir) 156 srcdir = os.path.join(buildconfig.topsrcdir, relobjdir) 157 module_ver = os.path.join(srcdir, "module.ver") 158 if os.path.exists(module_ver): 159 deps.add(module_ver) 160 overrides = parse_module_ver(module_ver, defines) 161 else: 162 overrides = {} 163 164 if rcinclude: 165 include = "// From included resource {}\n{}".format( 166 rcinclude, preprocess(rcinclude, defines).read() 167 ) 168 else: 169 include = "" 170 171 data = TEMPLATE.format( 172 include=include, 173 fileversion=overrides.get("WIN32_MODULE_FILEVERSION", milestone_winversion), 174 productversion=overrides.get( 175 "WIN32_MODULE_PRODUCTVERSION", milestone_winversion 176 ), 177 fileflags=" | ".join(flags), 178 comment=overrides.get("WIN32_MODULE_COMMENT", ""), 179 copyright=overrides.get("WIN32_MODULE_COPYRIGHT", "License: MPL 2"), 180 company=overrides.get("WIN32_MODULE_COMPANYNAME", "Mozilla Foundation"), 181 description=overrides.get("WIN32_MODULE_DESCRIPTION", ""), 182 mfversion=overrides.get("WIN32_MODULE_FILEVERSION_STRING", milestone_string), 183 mpversion=overrides.get("WIN32_MODULE_PRODUCTVERSION_STRING", milestone_string), 184 module=overrides.get("WIN32_MODULE_NAME", ""), 185 trademarks=overrides.get("WIN32_MODULE_TRADEMARKS", "Mozilla"), 186 binary=overrides.get("WIN32_MODULE_ORIGINAL_FILENAME", binary), 187 productname=overrides.get("WIN32_MODULE_PRODUCTNAME", display_name), 188 buildid=buildid, 189 ) 190 191 manifest_id = "2" if binary.lower().endswith(".dll") else "1" 192 if binary and not has_manifest(data, manifest_id): 193 manifest_path = os.path.join(srcdir, binary + ".manifest") 194 if os.path.exists(manifest_path): 195 manifest_path = manifest_path.replace("\\", "\\\\") 196 data += '\n{} RT_MANIFEST "{}"\n'.format(manifest_id, manifest_path) 197 198 with io.open("{}.rc".format(binary or "module"), "w", encoding="latin1") as fh: 199 fh.write(data) 200 201 202if __name__ == "__main__": 203 generate_module_rc(*sys.argv[1:]) 204