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
5# This module produces a JSON file that provides basic build info and
6# configuration metadata.
7
8from __future__ import absolute_import
9
10import os
11import re
12import json
13
14
15def build_dict(config, env=os.environ):
16    """
17    Build a dict containing data about the build configuration from
18    the environment.
19    """
20    substs = config.substs
21
22    # Check that all required variables are present first.
23    required = ["TARGET_CPU", "OS_TARGET"]
24    missing = [r for r in required if r not in substs]
25    if missing:
26        raise Exception("Missing required environment variables: %s" %
27                        ', '.join(missing))
28
29    d = {}
30    d['topsrcdir'] = config.topsrcdir
31
32    if config.mozconfig:
33        d['mozconfig'] = config.mozconfig
34
35    # os
36    o = substs["OS_TARGET"]
37    known_os = {"Linux": "linux",
38                "WINNT": "win",
39                "Darwin": "mac",
40                "Android": "android"}
41    if o in known_os:
42        d["os"] = known_os[o]
43    else:
44        # Allow unknown values, just lowercase them.
45        d["os"] = o.lower()
46
47    # Widget toolkit, just pass the value directly through.
48    d["toolkit"] = substs.get("MOZ_WIDGET_TOOLKIT")
49
50    # Application name
51    if 'MOZ_APP_NAME' in substs:
52        d["appname"] = substs["MOZ_APP_NAME"]
53
54    # Build app name
55    if 'MOZ_MULET' in substs and substs.get('MOZ_MULET') == "1":
56        d["buildapp"] = "mulet"
57    elif 'MOZ_BUILD_APP' in substs:
58        d["buildapp"] = substs["MOZ_BUILD_APP"]
59
60    # processor
61    p = substs["TARGET_CPU"]
62    # do some slight massaging for some values
63    #TODO: retain specific values in case someone wants them?
64    if p.startswith("arm"):
65        p = "arm"
66    elif re.match("i[3-9]86", p):
67        p = "x86"
68    d["processor"] = p
69    # hardcoded list of 64-bit CPUs
70    if p in ["x86_64", "ppc64"]:
71        d["bits"] = 64
72    # hardcoded list of known 32-bit CPUs
73    elif p in ["x86", "arm", "ppc"]:
74        d["bits"] = 32
75    # other CPUs will wind up with unknown bits
76
77    d['debug'] = substs.get('MOZ_DEBUG') == '1'
78    d['nightly_build'] = substs.get('NIGHTLY_BUILD') == '1'
79    d['release_or_beta'] = substs.get('RELEASE_OR_BETA') == '1'
80    d['devedition'] = substs.get('MOZ_DEV_EDITION') == '1'
81    d['pgo'] = substs.get('MOZ_PGO') == '1'
82    d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
83    d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
84    d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
85    d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'
86    d['stylo'] = substs.get('MOZ_STYLO_ENABLE') == '1'
87    d['asan'] = substs.get('MOZ_ASAN') == '1'
88    d['tsan'] = substs.get('MOZ_TSAN') == '1'
89    d['ubsan'] = substs.get('MOZ_UBSAN') == '1'
90    d['telemetry'] = substs.get('MOZ_TELEMETRY_REPORTING') == '1'
91    d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
92    d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
93    d['addon_signing'] = substs.get('MOZ_ADDON_SIGNING') == '1'
94    d['require_signing'] = substs.get('MOZ_REQUIRE_SIGNING') == '1'
95    d['allow_legacy_extensions'] = substs.get('MOZ_ALLOW_LEGACY_EXTENSIONS') == '1'
96    d['official'] = bool(substs.get('MOZILLA_OFFICIAL'))
97    d['updater'] = substs.get('MOZ_UPDATER') == '1'
98    d['artifact'] = substs.get('MOZ_ARTIFACT_BUILDS') == '1'
99    d['ccov'] = substs.get('MOZ_CODE_COVERAGE') == '1'
100
101    def guess_platform():
102        if d['buildapp'] in ('browser', 'mulet'):
103            p = d['os']
104            if p == 'mac':
105                p = 'macosx64'
106            elif d['bits'] == 64:
107                p = '{}64'.format(p)
108            elif p in ('win',):
109                p = '{}32'.format(p)
110
111            if d['buildapp'] == 'mulet':
112                p = '{}-mulet'.format(p)
113
114            if d['asan']:
115                p = '{}-asan'.format(p)
116
117            return p
118
119        if d['buildapp'] == 'mobile/android':
120            if d['processor'] == 'x86':
121                return 'android-x86'
122            return 'android-arm'
123
124    def guess_buildtype():
125        if d['debug']:
126            return 'debug'
127        if d['pgo']:
128            return 'pgo'
129        return 'opt'
130
131    # if buildapp or bits are unknown, we don't have a configuration similar to
132    # any in automation and the guesses are useless.
133    if 'buildapp' in d and (d['os'] == 'mac' or 'bits' in d):
134        d['platform_guess'] = guess_platform()
135        d['buildtype_guess'] = guess_buildtype()
136
137    if 'buildapp' in d and d['buildapp'] == 'mobile/android' and 'MOZ_ANDROID_MIN_SDK_VERSION' in substs:
138        d['android_min_sdk'] = substs['MOZ_ANDROID_MIN_SDK_VERSION']
139
140    return d
141
142
143def write_mozinfo(file, config, env=os.environ):
144    """Write JSON data about the configuration specified in config and an
145    environment variable dict to |file|, which may be a filename or file-like
146    object.
147    See build_dict for information about what  environment variables are used,
148    and what keys are produced.
149    """
150    build_conf = build_dict(config, env)
151    if isinstance(file, basestring):
152        file = open(file, 'wb')
153
154    json.dump(build_conf, file, sort_keys=True, indent=4)
155