Bug 1313306 - Allow @depends(when=something) without additional dependencies. r=chmanchester
Also allow when=True/False to avoid the chicken-egg problem of using
a generic `when` to use in replacement of @depends('--help') for things
like @dependable.
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -279,16 +279,20 @@ class ConfigureSandbox(dict):
}
log_namespace['queue_debug'] = queue_debug
self.log_impl = ReadOnlyNamespace(**log_namespace)
self._help = None
self._help_option = self.option_impl('--help',
help='print this message')
self._seen.add(self._help_option)
+
+ self._always = DependsFunction(self, lambda: True, [])
+ self._never = DependsFunction(self, lambda: False, [])
+
if self._value_for(self._help_option):
self._help = HelpFormatter(argv[0])
self._help.add(self._help_option)
elif moz_logger:
handler = logging.FileHandler('config.log', mode='w', delay=True)
handler.setFormatter(formatter)
logger.addHandler(handler)
@@ -489,17 +493,21 @@ class ConfigureSandbox(dict):
else:
raise TypeError(
"Cannot use object of type '%s' as %sargument to %s"
% (type(arg).__name__, '`%s` ' % arg_name if arg_name else '',
callee_name))
return arg
def _normalize_when(self, when, callee_name):
- if when is not None:
+ if when is True:
+ when = self._always
+ elif when is False:
+ when = self._never
+ elif when is not None:
when = self._dependency(when, callee_name, 'when')
if self._default_conditions:
# Create a pseudo @depends function for the combination of all
# default conditions and `when`.
dependencies = [when] if when else []
dependencies.extend(self._default_conditions)
if len(dependencies) == 1:
@@ -566,27 +574,27 @@ class ConfigureSandbox(dict):
function results corresponding to each of the arguments to @depends.
As an exception, when a HelpFormatter is attached, only functions that
have '--help' in their @depends argument list are called.
The decorated function is altered to use a different global namespace
for its execution. This different global namespace exposes a limited
set of functions from os.path.
'''
- if not args:
- raise ConfigureError('@depends needs at least one argument')
-
for k in kwargs:
if k != 'when':
raise TypeError(
"depends_impl() got an unexpected keyword argument '%s'"
% k)
when = self._normalize_when(kwargs.get('when'), '@depends')
+ if not when and not args:
+ raise ConfigureError('@depends needs at least one argument')
+
dependencies = tuple(self._dependency(arg, '@depends') for arg in args)
conditions = [
self._conditions[d]
for d in dependencies
if d in self._conditions and isinstance(d, Option)
]
for c in conditions:
--- a/python/mozbuild/mozbuild/configure/lint.py
+++ b/python/mozbuild/mozbuild/configure/lint.py
@@ -29,17 +29,18 @@ class LintSandbox(ConfigureSandbox):
def run(self, path=None):
if path:
self.include_file(path)
def _missing_help_dependency(self, obj):
if isinstance(obj, CombinedDependsFunction):
return False
if isinstance(obj, DependsFunction):
- if self._help_option in obj.dependencies:
+ if (self._help_option in obj.dependencies or
+ obj in (self._always, self._never)):
return False
func = self._wrapped[obj.func]
# We allow missing --help dependencies for functions that:
# - don't use @imports
# - don't have a closure
# - don't use global variables
if func in self._imports or func.func_closure:
return True
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -400,27 +400,27 @@ class TestChecksConfigure(unittest.TestC
with self.assertRaises(ConfigureError) as e:
self.get_result('check_prog("FOO", "foo")')
self.assertEqual(e.exception.message,
'progs must resolve to a list or tuple!')
with self.assertRaises(ConfigureError) as e:
self.get_result(
- 'foo = depends("--help")(lambda h: ("a", "b"))\n'
+ 'foo = depends(when=True)(lambda: ("a", "b"))\n'
'check_prog("FOO", ("known-a",), input=foo)'
)
self.assertEqual(e.exception.message,
'input must resolve to a tuple or a list with a '
'single element, or a string')
with self.assertRaises(ConfigureError) as e:
self.get_result(
- 'foo = depends("--help")(lambda h: {"a": "b"})\n'
+ 'foo = depends(when=True)(lambda: {"a": "b"})\n'
'check_prog("FOO", ("known-a",), input=foo)'
)
self.assertEqual(e.exception.message,
'input must resolve to a tuple or a list with a '
'single element, or a string')
def test_check_prog_with_path(self):
--- a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
+++ b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
@@ -42,36 +42,36 @@ class BaseCompileChecks(unittest.TestCas
os.path.abspath('/usr/bin/mockcc'): self.get_mock_compiler(
expected_test_content=expected_test_content,
expected_flags=expected_flags),
}
base_dir = os.path.join(topsrcdir, 'build', 'moz.configure')
mock_compiler_defs = textwrap.dedent('''\
- @depends('--help')
- def extra_toolchain_flags(_):
+ @depends(when=True)
+ def extra_toolchain_flags():
return []
include('%s/compilers-util.configure')
@compiler_class
- @depends('--help')
- def c_compiler(_):
+ @depends(when=True)
+ def c_compiler():
return namespace(
flags=[],
type='gcc',
compiler=os.path.abspath('/usr/bin/mockcc'),
wrapper=[],
language='C',
)
@compiler_class
- @depends('--help')
- def cxx_compiler(_):
+ @depends(when=True)
+ def cxx_compiler():
return namespace(
flags=[],
type='gcc',
compiler=os.path.abspath('/usr/bin/mockcc'),
wrapper=[],
language='C++',
)
''' % mozpath.normsep(base_dir))
@@ -305,33 +305,33 @@ class TestWarningChecks(BaseCompileCheck
'_WARNINGS_CXXFLAGS': ['-Wfoo'],
})
self.assertEqual(out, textwrap.dedent('''\
checking whether the C++ compiler supports -Wfoo... yes
'''))
def test_check_and_add_gcc_warning_when(self):
cmd = textwrap.dedent('''\
- @depends('--help')
- def never(_):
+ @depends(when=True)
+ def never():
return False
check_and_add_gcc_warning('-Wfoo', cxx_compiler, when=never)
''') + self.get_warnings()
config, out, status = self.do_compile_test(cmd)
self.assertEqual(status, 0)
self.assertEqual(config, {
'_WARNINGS_CFLAGS': [],
'_WARNINGS_CXXFLAGS': [],
})
self.assertEqual(out, '')
cmd = textwrap.dedent('''\
- @depends('--help')
- def always(_):
+ @depends(when=True)
+ def always():
return True
check_and_add_gcc_warning('-Wfoo', cxx_compiler, when=always)
''') + self.get_warnings()
config, out, status = self.do_compile_test(cmd)
self.assertEqual(status, 0)
self.assertEqual(config, {
'_WARNINGS_CFLAGS': [],
@@ -364,33 +364,33 @@ class TestWarningChecks(BaseCompileCheck
self.assertEqual(config, {
'_WARNINGS_CFLAGS': ['-Wfoo'],
'_WARNINGS_CXXFLAGS': [],
})
self.assertEqual(out, '')
def test_add_gcc_warning_when(self):
cmd = textwrap.dedent('''\
- @depends('--help')
- def never(_):
+ @depends(when=True)
+ def never():
return False
add_gcc_warning('-Wfoo', c_compiler, when=never)
''') + self.get_warnings()
config, out, status = self.do_compile_test(cmd)
self.assertEqual(status, 0)
self.assertEqual(config, {
'_WARNINGS_CFLAGS': [],
'_WARNINGS_CXXFLAGS': [],
})
self.assertEqual(out, '')
cmd = textwrap.dedent('''\
- @depends('--help')
- def always(_):
+ @depends(when=True)
+ def always():
return True
add_gcc_warning('-Wfoo', c_compiler, when=always)
''') + self.get_warnings()
config, out, status = self.do_compile_test(cmd)
self.assertEqual(status, 0)
self.assertEqual(config, {
'_WARNINGS_CFLAGS': ['-Wfoo'],
--- a/python/mozbuild/mozbuild/test/configure/test_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_configure.py
@@ -425,25 +425,19 @@ class TestConfigure(unittest.TestCase):
with self.assertRaises(ConfigureError):
# Both --set-foo and --set-name=FOO are going to try to
# set_config('FOO'...)
get_config(['--set-foo', '--set-name=FOO'])
def test_set_config_when(self):
with self.moz_configure('''
- @depends('--help')
- def always(_):
- return True
- @depends('--help')
- def never(_):
- return False
option('--with-qux', help='qux')
- set_config('FOO', 'foo', when=always)
- set_config('BAR', 'bar', when=never)
+ set_config('FOO', 'foo', when=True)
+ set_config('BAR', 'bar', when=False)
set_config('QUX', 'qux', when='--with-qux')
'''):
config = self.get_config()
self.assertEquals(config, {
'FOO': 'foo',
})
config = self.get_config(['--with-qux'])
self.assertEquals(config, {
@@ -480,25 +474,19 @@ class TestConfigure(unittest.TestCase):
with self.assertRaises(ConfigureError):
# Both --set-foo and --set-name=FOO are going to try to
# set_define('FOO'...)
get_config(['--set-foo', '--set-name=FOO'])
def test_set_define_when(self):
with self.moz_configure('''
- @depends('--help')
- def always(_):
- return True
- @depends('--help')
- def never(_):
- return False
option('--with-qux', help='qux')
- set_define('FOO', 'foo', when=always)
- set_define('BAR', 'bar', when=never)
+ set_define('FOO', 'foo', when=True)
+ set_define('BAR', 'bar', when=False)
set_define('QUX', 'qux', when='--with-qux')
'''):
config = self.get_config()
self.assertEquals(config['DEFINES'], {
'FOO': 'foo',
})
config = self.get_config(['--with-qux'])
self.assertEquals(config['DEFINES'], {
@@ -756,28 +744,22 @@ class TestConfigure(unittest.TestCase):
self.assertEquals(
e.exception.message,
'Option `--with-foo` already defined'
)
def test_option_when(self):
with self.moz_configure('''
- @depends('--help')
- def always(_):
- return True
- @depends('--help')
- def never(_):
- return False
- option('--with-foo', help='foo', when=always)
- option('--with-bar', help='bar', when=never)
+ option('--with-foo', help='foo', when=True)
+ option('--with-bar', help='bar', when=False)
option('--with-qux', env="QUX", help='qux', when='--with-foo')
- set_config('FOO', depends('--with-foo', when=always)(lambda x: x))
- set_config('BAR', depends('--with-bar', when=never)(lambda x: x))
+ set_config('FOO', depends('--with-foo', when=True)(lambda x: x))
+ set_config('BAR', depends('--with-bar', when=False)(lambda x: x))
set_config('QUX', depends('--with-qux', when='--with-foo')(lambda x: x))
'''):
config = self.get_config()
self.assertEquals(config, {
'FOO': NegativeOptionValue(),
})
config = self.get_config(['--with-foo'])
@@ -840,35 +822,32 @@ class TestConfigure(unittest.TestCase):
--help print this message
--with-foo foo
--with-qux qux
Environment variables:
'''))
with self.moz_configure('''
- @depends('--help')
- def always(_):
- return True
- option('--with-foo', help='foo', when=always)
+ option('--with-foo', help='foo', when=True)
set_config('FOO', depends('--with-foo')(lambda x: x))
'''):
with self.assertRaises(ConfigureError) as e:
self.get_config()
self.assertEquals(e.exception.message,
'@depends function needs the same `when` as '
'options it depends on')
with self.moz_configure('''
- @depends('--help')
- def always(_):
+ @depends(when=True)
+ def always():
return True
- @depends('--help')
- def always2(_):
+ @depends(when=True)
+ def always2():
return True
option('--with-foo', help='foo', when=always)
set_config('FOO', depends('--with-foo', when=always2)(lambda x: x))
'''):
with self.assertRaises(ConfigureError) as e:
self.get_config()
self.assertEquals(e.exception.message,
@@ -908,27 +887,20 @@ class TestConfigure(unittest.TestCase):
'''):
self.get_config()
self.assertEquals(e.exception.message, "Unexpected type: 'int'")
def test_include_when(self):
with MockedOpen({
os.path.join(test_data_path, 'moz.configure'): textwrap.dedent('''
- @depends('--help')
- def always(_):
- return True
- @depends('--help')
- def never(_):
- return False
-
option('--with-foo', help='foo')
- include('always.configure', when=always)
- include('never.configure', when=never)
+ include('always.configure', when=True)
+ include('never.configure', when=False)
include('foo.configure', when='--with-foo')
set_config('FOO', foo)
set_config('BAR', bar)
set_config('QUX', qux)
'''),
os.path.join(test_data_path, 'always.configure'): textwrap.dedent('''
option('--with-bar', help='bar')
@@ -1090,38 +1062,31 @@ class TestConfigure(unittest.TestCase):
'''):
self.get_config()
self.assertEquals(e.exception.message,
"depends_impl() got an unexpected keyword argument 'foo'")
def test_depends_when(self):
with self.moz_configure('''
- @depends('--help')
- def always(_):
- return True
- @depends('--help')
- def never(_):
- return False
-
- @depends('--help', when=always)
- def foo(_):
+ @depends(when=True)
+ def foo():
return 'foo'
set_config('FOO', foo)
- @depends('--help', when=never)
- def bar(_):
+ @depends(when=False)
+ def bar():
return 'bar'
set_config('BAR', bar)
option('--with-qux', help='qux')
- @depends('--help', when='--with-qux')
- def qux(_):
+ @depends(when='--with-qux')
+ def qux():
return 'qux'
set_config('QUX', qux)
'''):
config = self.get_config()
self.assertEquals(config, {
'FOO': 'foo',
})