Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
# 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
import os
import shutil
import sys
import unittest
from contextlib import contextmanager
from tempfile import mkdtemp
import buildconfig
import mozpack.path as mozpath
import six
from mozfile import which
from mozpack.files import FileFinder
from mozunit import main
from mozbuild.backend import get_backend_class
from mozbuild.backend.configenvironment import ConfigEnvironment
from mozbuild.backend.fastermake import FasterMakeBackend
from mozbuild.backend.recursivemake import RecursiveMakeBackend
from mozbuild.base import MozbuildObject
from mozbuild.dirutils import ensureParentDir
from mozbuild.frontend.emitter import TreeMetadataEmitter
from mozbuild.frontend.reader import BuildReader
def make_path():
try:
return buildconfig.substs["GMAKE"]
except KeyError:
fetches_dir = os.environ.get("MOZ_FETCHES_DIR")
extra_search_dirs = ()
if fetches_dir:
extra_search_dirs = (os.path.join(fetches_dir, "mozmake"),)
# Fallback for when running the test without an objdir.
for name in ("gmake", "make", "mozmake", "gnumake", "mingw32-make"):
path = which(name, extra_search_dirs=extra_search_dirs)
if path:
return path
BASE_SUBSTS = [
("PYTHON", mozpath.normsep(sys.executable)),
("PYTHON3", mozpath.normsep(sys.executable)),
("MOZ_UI_LOCALE", "en-US"),
("GMAKE", make_path()),
]
class TestBuild(unittest.TestCase):
def setUp(self):
self._old_env = dict(os.environ)
os.environ.pop("MOZCONFIG", None)
os.environ.pop("MOZ_OBJDIR", None)
os.environ.pop("MOZ_PGO", None)
def tearDown(self):
os.environ.clear()
os.environ.update(self._old_env)
@contextmanager
def do_test_backend(self, *backends, **kwargs):
# Create the objdir in the srcdir to ensure that they share
# the same drive on Windows.
topobjdir = mkdtemp(dir=buildconfig.topsrcdir)
try:
config = ConfigEnvironment(buildconfig.topsrcdir, topobjdir, **kwargs)
reader = BuildReader(config)
emitter = TreeMetadataEmitter(config)
moz_build = mozpath.join(config.topsrcdir, "test.mozbuild")
definitions = list(emitter.emit(reader.read_mozbuild(moz_build, config)))
for backend in backends:
backend(config).consume(definitions)
yield config
except Exception:
raise
finally:
if not os.environ.get("MOZ_NO_CLEANUP"):
shutil.rmtree(topobjdir)
@contextmanager
def line_handler(self):
lines = []
def handle_make_line(line):
lines.append(line)
try:
yield handle_make_line
except Exception:
print("\n".join(lines))
raise
if os.environ.get("MOZ_VERBOSE_MAKE"):
print("\n".join(lines))
def test_recursive_make(self):
substs = list(BASE_SUBSTS)
with self.do_test_backend(RecursiveMakeBackend, substs=substs) as config:
build = MozbuildObject(config.topsrcdir, None, None, config.topobjdir)
build._config_environment = config
overrides = [
"install_manifest_depends=",
"MOZ_JAR_MAKER_FILE_FORMAT=flat",
"TEST_MOZBUILD=1",
]
with self.line_handler() as handle_make_line:
build._run_make(
directory=config.topobjdir,
target=overrides,
silent=False,
line_handler=handle_make_line,
)
self.validate(config)
def test_faster_recursive_make(self):
substs = list(BASE_SUBSTS) + [
("BUILD_BACKENDS", "FasterMake+RecursiveMake"),
]
with self.do_test_backend(
get_backend_class("FasterMake+RecursiveMake"), substs=substs
) as config:
buildid = mozpath.join(config.topobjdir, "config", "buildid")
ensureParentDir(buildid)
with open(buildid, "w") as fh:
fh.write("20100101012345\n")
build = MozbuildObject(config.topsrcdir, None, None, config.topobjdir)
build._config_environment = config
overrides = [
"install_manifest_depends=",
"MOZ_JAR_MAKER_FILE_FORMAT=flat",
"TEST_MOZBUILD=1",
]
with self.line_handler() as handle_make_line:
build._run_make(
directory=config.topobjdir,
target=overrides,
silent=False,
line_handler=handle_make_line,
)
self.validate(config)
def test_faster_make(self):
substs = list(BASE_SUBSTS) + [
("MOZ_BUILD_APP", "dummy_app"),
("MOZ_WIDGET_TOOLKIT", "dummy_widget"),
]
with self.do_test_backend(
RecursiveMakeBackend, FasterMakeBackend, substs=substs
) as config:
buildid = mozpath.join(config.topobjdir, "config", "buildid")
ensureParentDir(buildid)
with open(buildid, "w") as fh:
fh.write("20100101012345\n")
build = MozbuildObject(config.topsrcdir, None, None, config.topobjdir)
build._config_environment = config
overrides = [
"TEST_MOZBUILD=1",
]
with self.line_handler() as handle_make_line:
build._run_make(
directory=mozpath.join(config.topobjdir, "faster"),
target=overrides,
silent=False,
line_handler=handle_make_line,
)
self.validate(config)
def validate(self, config):
self.maxDiff = None
test_path = mozpath.join(
"$SRCDIR",
"python",
"mozbuild",
"mozbuild",
"test",
"backend",
"data",
"build",
)
result = {
p: six.ensure_text(f.open().read())
for p, f in FileFinder(mozpath.join(config.topobjdir, "dist"))
}
self.assertTrue(len(result))
self.assertEqual(
result,
{
"bin/baz.ini": "baz.ini: FOO is foo\n",
"bin/child/bar.ini": "bar.ini\n",
"bin/child2/foo.css": "foo.css: FOO is foo\n",
"bin/child2/qux.ini": "qux.ini: BAR is not defined\n",
"bin/chrome.manifest": "manifest chrome/foo.manifest\n"
"manifest components/components.manifest\n",
"bin/chrome/foo.manifest": "content bar foo/child/\n"
"content foo foo/\n"
"bin/chrome/foo/bar.js": "bar.js\n",
"bin/chrome/foo/child/baz.jsm": '//@line 2 "%s/baz.jsm"\nbaz.jsm: FOO is foo\n'
% (test_path),
"bin/chrome/foo/child/hoge.js": '//@line 2 "%s/bar.js"\nbar.js: FOO is foo\n'
% (test_path),
"bin/chrome/foo/foo.css": "foo.css: FOO is foo\n",
"bin/chrome/foo/foo.js": "foo.js\n",
"bin/chrome/foo/qux.js": "bar.js\n",
"bin/components/bar.js": '//@line 2 "%s/bar.js"\nbar.js: FOO is foo\n'
% (test_path),
"bin/components/components.manifest": "component {foo} foo.js\ncomponent {bar} bar.js\n", # NOQA: E501
"bin/components/foo.js": "foo.js\n",
"bin/defaults/pref/prefs.js": "prefs.js\n",
"bin/foo.ini": "foo.ini\n",
"bin/modules/baz.jsm": '//@line 2 "%s/baz.jsm"\nbaz.jsm: FOO is foo\n'
% (test_path),
"bin/modules/child/bar.jsm": "bar.jsm\n",
"bin/modules/child2/qux.jsm": '//@line 4 "%s/qux.jsm"\nqux.jsm: BAR is not defined\n' # NOQA: E501
% (test_path),
"bin/modules/foo.jsm": "foo.jsm\n",
"bin/res/resource": "resource\n",
"bin/res/child/resource2": "resource2\n",
"bin/app/baz.ini": "baz.ini: FOO is bar\n",
"bin/app/child/bar.ini": "bar.ini\n",
"bin/app/child2/qux.ini": "qux.ini: BAR is defined\n",
"bin/app/chrome.manifest": "manifest chrome/foo.manifest\n"
"manifest components/components.manifest\n",
"bin/app/chrome/foo.manifest": "content bar foo/child/\n"
"content foo foo/\n"
"bin/app/chrome/foo/bar.js": "bar.js\n",
"bin/app/chrome/foo/child/baz.jsm": '//@line 2 "%s/baz.jsm"\nbaz.jsm: FOO is bar\n'
% (test_path),
"bin/app/chrome/foo/child/hoge.js": '//@line 2 "%s/bar.js"\nbar.js: FOO is bar\n'
% (test_path),
"bin/app/chrome/foo/foo.css": "foo.css: FOO is bar\n",
"bin/app/chrome/foo/foo.js": "foo.js\n",
"bin/app/chrome/foo/qux.js": "bar.js\n",
"bin/app/components/bar.js": '//@line 2 "%s/bar.js"\nbar.js: FOO is bar\n'
% (test_path),
"bin/app/components/components.manifest": "component {foo} foo.js\ncomponent {bar} bar.js\n", # NOQA: E501
"bin/app/components/foo.js": "foo.js\n",
"bin/app/defaults/preferences/prefs.js": "prefs.js\n",
"bin/app/foo.css": "foo.css: FOO is bar\n",
"bin/app/foo.ini": "foo.ini\n",
"bin/app/modules/baz.jsm": '//@line 2 "%s/baz.jsm"\nbaz.jsm: FOO is bar\n'
% (test_path),
"bin/app/modules/child/bar.jsm": "bar.jsm\n",
"bin/app/modules/child2/qux.jsm": '//@line 2 "%s/qux.jsm"\nqux.jsm: BAR is defined\n' # NOQA: E501
% (test_path),
"bin/app/modules/foo.jsm": "foo.jsm\n",
},
)
if __name__ == "__main__":
main()