Bug 902619 - Write mozinfo.json as part of config.status; r=ted

There are both mechanical and logical changes in this patch.

The mechanical changes involve moving some files into the mozbuild
package.

The logical changes include move writing of mozinfo.json into
config.status (from configure.in). There were some variable assignments
being performed in configure.in. These variables were read from
writemozinfo.py. However, these variables don't appear to be necessary!
Now that mozinfo has full access to the underlying config.status data
structure, it can now access these variables directly. I verified that
every variable being assigned in configure.in had a corresponding
AC_SUBST earlier in the file.

The only variable that's a bit weird is the TOPSRCDIR and MOZCONFIG
environment variables. mozinfo continues to look in the environment for
MOZCONFIG. However TOPSRCDIR is now coming from config.status.

As part of moving the code, I also modernized the test file, cleaned up
some style, and removed some unused imports.

--HG--
rename : config/writemozinfo.py => python/mozbuild/mozbuild/mozinfo.py
rename : config/tests/unit-writemozinfo.py => python/mozbuild/mozbuild/test/test_mozinfo.py
This commit is contained in:
Gregory Szorc 2013-08-07 23:48:41 -07:00
parent 15e10eee08
commit 2a1982cb93
6 changed files with 298 additions and 255 deletions

View File

@ -19,8 +19,7 @@ from mozbuild.backend.configenvironment import ConfigEnvironment
from mozbuild.backend.recursivemake import RecursiveMakeBackend
from mozbuild.frontend.emitter import TreeMetadataEmitter
from mozbuild.frontend.reader import BuildReader
from Preprocessor import Preprocessor
from mozbuild.mozinfo import write_mozinfo
log_manager = LoggingManager()
@ -87,6 +86,11 @@ def config_status(topobjdir = '.', topsrcdir = '.',
env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
non_global_defines=non_global_defines, substs=substs)
# mozinfo.json only needs written if configure changes and configure always
# passes this environment variable.
if 'WRITE_MOZINFO' in os.environ:
write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
reader = BuildReader(env)
emitter = TreeMetadataEmitter(env)
backend = RecursiveMakeBackend(env)

View File

@ -1,204 +0,0 @@
#!/usr/bin/env python
import unittest
import json, os, sys, time, tempfile
from StringIO import StringIO
import mozunit
from writemozinfo import build_dict, write_json
class TestBuildDict(unittest.TestCase):
def testMissing(self):
"""
Test that missing required values raises.
"""
self.assertRaises(Exception, build_dict, {'OS_TARGET':'foo'})
self.assertRaises(Exception, build_dict, {'TARGET_CPU':'foo'})
self.assertRaises(Exception, build_dict, {'MOZ_WIDGET_TOOLKIT':'foo'})
def testWin(self):
d = build_dict({'OS_TARGET':'WINNT',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'windows'})
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual(32, d['bits'])
def testLinux(self):
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual('linux', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('gtk2', d['toolkit'])
self.assertEqual(32, d['bits'])
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'x86_64',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual('linux', d['os'])
self.assertEqual('x86_64', d['processor'])
self.assertEqual('gtk2', d['toolkit'])
self.assertEqual(64, d['bits'])
def testMac(self):
d = build_dict({'OS_TARGET':'Darwin',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'cocoa'})
self.assertEqual('mac', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertEqual(32, d['bits'])
d = build_dict({'OS_TARGET':'Darwin',
'TARGET_CPU':'x86_64',
'MOZ_WIDGET_TOOLKIT':'cocoa'})
self.assertEqual('mac', d['os'])
self.assertEqual('x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertEqual(64, d['bits'])
def testMacUniversal(self):
d = build_dict({'OS_TARGET':'Darwin',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'cocoa',
'UNIVERSAL_BINARY': '1'})
self.assertEqual('mac', d['os'])
self.assertEqual('universal-x86-x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertFalse('bits' in d)
d = build_dict({'OS_TARGET':'Darwin',
'TARGET_CPU':'x86_64',
'MOZ_WIDGET_TOOLKIT':'cocoa',
'UNIVERSAL_BINARY': '1'})
self.assertEqual('mac', d['os'])
self.assertEqual('universal-x86-x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertFalse('bits' in d)
def testAndroid(self):
d = build_dict({'OS_TARGET':'Android',
'TARGET_CPU':'arm',
'MOZ_WIDGET_TOOLKIT':'android'})
self.assertEqual('android', d['os'])
self.assertEqual('arm', d['processor'])
self.assertEqual('android', d['toolkit'])
self.assertEqual(32, d['bits'])
def testX86(self):
"""
Test that various i?86 values => x86.
"""
d = build_dict({'OS_TARGET':'WINNT',
'TARGET_CPU':'i486',
'MOZ_WIDGET_TOOLKIT':'windows'})
self.assertEqual('x86', d['processor'])
d = build_dict({'OS_TARGET':'WINNT',
'TARGET_CPU':'i686',
'MOZ_WIDGET_TOOLKIT':'windows'})
self.assertEqual('x86', d['processor'])
def testARM(self):
"""
Test that all arm CPU architectures => arm.
"""
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'arm',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual('arm', d['processor'])
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'armv7',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual('arm', d['processor'])
def testUnknown(self):
"""
Test that unknown values pass through okay.
"""
d = build_dict({'OS_TARGET':'RandOS',
'TARGET_CPU':'cptwo',
'MOZ_WIDGET_TOOLKIT':'foobar'})
self.assertEqual("randos", d["os"])
self.assertEqual("cptwo", d["processor"])
self.assertEqual("foobar", d["toolkit"])
# unknown CPUs should not get a bits value
self.assertFalse("bits" in d)
def testDebug(self):
"""
Test that debug values are properly detected.
"""
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual(False, d['debug'])
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'gtk2',
'MOZ_DEBUG':'1'})
self.assertEqual(True, d['debug'])
def testCrashreporter(self):
"""
Test that crashreporter values are properly detected.
"""
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'gtk2'})
self.assertEqual(False, d['crashreporter'])
d = build_dict({'OS_TARGET':'Linux',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'gtk2',
'MOZ_CRASHREPORTER':'1'})
self.assertEqual(True, d['crashreporter'])
class TestWriteJson(unittest.TestCase):
"""
Test the write_json function.
"""
def setUp(self):
fd, self.f = tempfile.mkstemp()
os.close(fd)
def tearDown(self):
os.unlink(self.f)
def testBasic(self):
"""
Test that writing to a file produces correct output.
"""
write_json(self.f, env={'OS_TARGET':'WINNT',
'TARGET_CPU':'i386',
'TOPSRCDIR':'/tmp',
'MOZCONFIG':'foo',
'MOZ_WIDGET_TOOLKIT':'windows'})
with open(self.f) as f:
d = json.load(f)
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual('/tmp', d['topsrcdir'])
self.assertEqual(os.path.normpath('/tmp/foo'), d['mozconfig'])
self.assertEqual(32, d['bits'])
def testFileObj(self):
"""
Test that writing to a file-like object produces correct output.
"""
s = StringIO()
write_json(s, env={'OS_TARGET':'WINNT',
'TARGET_CPU':'i386',
'MOZ_WIDGET_TOOLKIT':'windows'})
d = json.loads(s.getvalue())
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual(32, d['bits'])
if __name__ == '__main__':
mozunit.main()

View File

@ -9054,7 +9054,9 @@ xpcom/xpcom-private.h
AC_SUBST(STLPORT_LIBS)
export WRITE_MOZINFO=1
AC_OUTPUT([mozilla-config.h])
unset WRITE_MOZINFO
# Hack around an Apple bug that affects the egrep that comes with OS X 10.7.
# "env ARCHPREFERENCE=i386,x86_64 arch egrep" first tries to use the 32-bit
@ -9201,24 +9203,6 @@ dnl so that regeneration via dependencies works correctly
fi
fi
# Generate a JSON config file for unittest harnesses etc to read
# build configuration details from in a standardized way.
OS_TARGET=${OS_TARGET} \
TARGET_CPU=${TARGET_CPU} \
MOZ_DEBUG=${MOZ_DEBUG} \
MOZ_WIDGET_TOOLKIT=${MOZ_WIDGET_TOOLKIT} \
UNIVERSAL_BINARY=${UNIVERSAL_BINARY} \
MOZ_CRASHREPORTER=${MOZ_CRASHREPORTER} \
MOZ_APP_NAME=${MOZ_APP_NAME} \
TOPSRCDIR=${_topsrcdir} \
MOZ_ASAN=${MOZ_ASAN} \
$PYTHON ${_topsrcdir}/config/writemozinfo.py ./mozinfo.json.tmp
if cmp -s ./mozinfo.json.tmp ./mozinfo.json; then
rm ./mozinfo.json.tmp
else
mv -f ./mozinfo.json.tmp ./mozinfo.json
fi
# Run jemalloc configure script
if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -o -n "$MOZ_REPLACE_MALLOC"; then

View File

@ -19,8 +19,7 @@ from mozbuild.backend.configenvironment import ConfigEnvironment
from mozbuild.backend.recursivemake import RecursiveMakeBackend
from mozbuild.frontend.emitter import TreeMetadataEmitter
from mozbuild.frontend.reader import BuildReader
from Preprocessor import Preprocessor
from mozbuild.mozinfo import write_mozinfo
log_manager = LoggingManager()
@ -87,6 +86,11 @@ def config_status(topobjdir = '.', topsrcdir = '.',
env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
non_global_defines=non_global_defines, substs=substs)
# mozinfo.json only needs written if configure changes and configure always
# passes this environment variable.
if 'WRITE_MOZINFO' in os.environ:
write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
reader = BuildReader(env)
emitter = TreeMetadataEmitter(env)
backend = RecursiveMakeBackend(env)

View File

@ -1,29 +1,21 @@
#!/usr/bin/env python
# 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/.
#
# This script is run during configure, taking variables set in configure
# and producing a JSON file that describes some portions of the build
# configuration, such as the target OS and CPU.
#
# The output file is intended to be used as input to the mozinfo package.
from __future__ import print_function
# This module produces a JSON file that provides basic build info and
# configuration metadata.
import os
import re
import sys
import json
import buildconfig
def build_dict(env=None):
def build_dict(config, env=os.environ):
"""
Build a dict containing data about the build configuration from
the environment.
"""
substs = env or buildconfig.substs
env = env or os.environ
substs = config.substs
# Check that all required variables are present first.
required = ["TARGET_CPU", "OS_TARGET", "MOZ_WIDGET_TOOLKIT"]
@ -33,12 +25,11 @@ def build_dict(env=None):
', '.join(missing))
d = {}
d['topsrcdir'] = substs.get('TOPSRCDIR', buildconfig.topsrcdir)
d['topsrcdir'] = config.topsrcdir
if 'MOZCONFIG' in env:
mozconfig = env["MOZCONFIG"]
if 'TOPSRCDIR' in env:
mozconfig = os.path.join(env["TOPSRCDIR"], mozconfig)
mozconfig = os.path.join(config.topsrcdir, mozconfig)
d['mozconfig'] = os.path.normpath(mozconfig)
# os
@ -89,24 +80,17 @@ def build_dict(env=None):
return d
def write_json(file, env=None):
"""
Write JSON data about the configuration specified in |env|
to |file|, which may be a filename or file-like object.
def write_mozinfo(file, config, env=os.environ):
"""Write JSON data about the configuration specified in config and an
environment variable dict to |file|, which may be a filename or file-like
object.
See build_dict for information about what environment variables are used,
and what keys are produced.
"""
build_conf = build_dict(env=env)
build_conf = build_dict(config, env)
if isinstance(file, basestring):
with open(file, "w") as f:
json.dump(build_conf, f)
else:
json.dump(build_conf, file)
if __name__ == '__main__':
try:
write_json(sys.argv[1] if len(sys.argv) > 1 else sys.stdout)
except Exception as e:
print(str(e), file=sys.stderr)
sys.exit(1)

View File

@ -0,0 +1,271 @@
#!/usr/bin/env python
# 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 json
import os
import tempfile
import unittest
from StringIO import StringIO
import mozunit
from mozbuild.backend.configenvironment import ConfigEnvironment
from mozbuild.mozinfo import (
build_dict,
write_mozinfo,
)
class Base(object):
def _config(self, substs={}):
d = os.path.dirname(__file__)
return ConfigEnvironment(d, d, substs=substs)
class TestBuildDict(unittest.TestCase, Base):
def test_missing(self):
"""
Test that missing required values raises.
"""
with self.assertRaises(Exception):
build_dict(self._config(substs=dict(OS_TARGET='foo')))
with self.assertRaises(Exception):
build_dict(self._config(substs=dict(TARGET_CPU='foo')))
with self.assertRaises(Exception):
build_dict(self._config(substs=dict(MOZ_WIDGET_TOOLKIT='foo')))
def test_win(self):
d = build_dict(self._config(dict(
OS_TARGET='WINNT',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='windows',
)))
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual(32, d['bits'])
def test_linux(self):
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual('linux', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('gtk2', d['toolkit'])
self.assertEqual(32, d['bits'])
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='x86_64',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual('linux', d['os'])
self.assertEqual('x86_64', d['processor'])
self.assertEqual('gtk2', d['toolkit'])
self.assertEqual(64, d['bits'])
def test_mac(self):
d = build_dict(self._config(dict(
OS_TARGET='Darwin',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='cocoa',
)))
self.assertEqual('mac', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertEqual(32, d['bits'])
d = build_dict(self._config(dict(
OS_TARGET='Darwin',
TARGET_CPU='x86_64',
MOZ_WIDGET_TOOLKIT='cocoa',
)))
self.assertEqual('mac', d['os'])
self.assertEqual('x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertEqual(64, d['bits'])
def test_mac_universal(self):
d = build_dict(self._config(dict(
OS_TARGET='Darwin',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='cocoa',
UNIVERSAL_BINARY='1',
)))
self.assertEqual('mac', d['os'])
self.assertEqual('universal-x86-x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertFalse('bits' in d)
d = build_dict(self._config(dict(
OS_TARGET='Darwin',
TARGET_CPU='x86_64',
MOZ_WIDGET_TOOLKIT='cocoa',
UNIVERSAL_BINARY='1',
)))
self.assertEqual('mac', d['os'])
self.assertEqual('universal-x86-x86_64', d['processor'])
self.assertEqual('cocoa', d['toolkit'])
self.assertFalse('bits' in d)
def test_android(self):
d = build_dict(self._config(dict(
OS_TARGET='Android',
TARGET_CPU='arm',
MOZ_WIDGET_TOOLKIT='android',
)))
self.assertEqual('android', d['os'])
self.assertEqual('arm', d['processor'])
self.assertEqual('android', d['toolkit'])
self.assertEqual(32, d['bits'])
def test_x86(self):
"""
Test that various i?86 values => x86.
"""
d = build_dict(self._config(dict(
OS_TARGET='WINNT',
TARGET_CPU='i486',
MOZ_WIDGET_TOOLKIT='windows',
)))
self.assertEqual('x86', d['processor'])
d = build_dict(self._config(dict(
OS_TARGET='WINNT',
TARGET_CPU='i686',
MOZ_WIDGET_TOOLKIT='windows',
)))
self.assertEqual('x86', d['processor'])
def test_arm(self):
"""
Test that all arm CPU architectures => arm.
"""
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='arm',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual('arm', d['processor'])
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='armv7',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual('arm', d['processor'])
def test_unknown(self):
"""
Test that unknown values pass through okay.
"""
d = build_dict(self._config(dict(
OS_TARGET='RandOS',
TARGET_CPU='cptwo',
MOZ_WIDGET_TOOLKIT='foobar',
)))
self.assertEqual("randos", d["os"])
self.assertEqual("cptwo", d["processor"])
self.assertEqual("foobar", d["toolkit"])
# unknown CPUs should not get a bits value
self.assertFalse("bits" in d)
def test_debug(self):
"""
Test that debug values are properly detected.
"""
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual(False, d['debug'])
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='gtk2',
MOZ_DEBUG='1',
)))
self.assertEqual(True, d['debug'])
def test_crashreporter(self):
"""
Test that crashreporter values are properly detected.
"""
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='gtk2',
)))
self.assertEqual(False, d['crashreporter'])
d = build_dict(self._config(dict(
OS_TARGET='Linux',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='gtk2',
MOZ_CRASHREPORTER='1',
)))
self.assertEqual(True, d['crashreporter'])
class TestWriteMozinfo(unittest.TestCase, Base):
"""
Test the write_mozinfo function.
"""
def setUp(self):
fd, self.f = tempfile.mkstemp()
os.close(fd)
def tearDown(self):
os.unlink(self.f)
def test_basic(self):
"""
Test that writing to a file produces correct output.
"""
c = self._config(dict(
OS_TARGET='WINNT',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='windows',
))
c.topsrcdir = '/tmp'
write_mozinfo(self.f, c, {'MOZCONFIG': 'foo'})
with open(self.f) as f:
d = json.load(f)
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual('/tmp', d['topsrcdir'])
self.assertEqual(os.path.normpath('/tmp/foo'), d['mozconfig'])
self.assertEqual(32, d['bits'])
def test_fileobj(self):
"""
Test that writing to a file-like object produces correct output.
"""
s = StringIO()
c = self._config(dict(
OS_TARGET='WINNT',
TARGET_CPU='i386',
MOZ_WIDGET_TOOLKIT='windows',
))
write_mozinfo(s, c)
d = json.loads(s.getvalue())
self.assertEqual('win', d['os'])
self.assertEqual('x86', d['processor'])
self.assertEqual('windows', d['toolkit'])
self.assertEqual(32, d['bits'])
if __name__ == '__main__':
mozunit.main()