Commit 7cde7f20 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

fail if unknown variables are used in a manifest

Summary:
Check that all variable names are valid when loading manifest files.
This ensures that getdeps.py will error out if someone makes a typo in a
variable name, rather than treating it as never equal to anything.

Reviewed By: pkaush

Differential Revision: D16477397

fbshipit-source-id: 030e0642ff4a08db8eb74a0a0223e03d53e4880f
parent 2a068f41
...@@ -12,7 +12,7 @@ import re ...@@ -12,7 +12,7 @@ import re
import shlex import shlex
def parse_expr(expr_text): def parse_expr(expr_text, valid_variables):
""" parses the simple criteria expression syntax used in """ parses the simple criteria expression syntax used in
dependency specifications. dependency specifications.
Returns an ExprNode instance that can be evaluated like this: Returns an ExprNode instance that can be evaluated like this:
...@@ -37,7 +37,7 @@ def parse_expr(expr_text): ...@@ -37,7 +37,7 @@ def parse_expr(expr_text):
# none of them evaluated true. # none of them evaluated true.
""" """
p = Parser(expr_text) p = Parser(expr_text, valid_variables)
return p.parse() return p.parse()
...@@ -112,9 +112,10 @@ class EqualExpr(ExprNode): ...@@ -112,9 +112,10 @@ class EqualExpr(ExprNode):
class Parser(object): class Parser(object):
def __init__(self, text): def __init__(self, text, valid_variables):
self.text = text self.text = text
self.lex = shlex.shlex(text) self.lex = shlex.shlex(text)
self.valid_variables = valid_variables
def parse(self): def parse(self):
expr = self.top() expr = self.top()
...@@ -141,6 +142,8 @@ class Parser(object): ...@@ -141,6 +142,8 @@ class Parser(object):
return func() return func()
if op == "=": if op == "=":
if name not in self.valid_variables:
raise Exception("unknown variable %r in expression" % (name,))
return EqualExpr(name, self.lex.get_token()) return EqualExpr(name, self.lex.get_token())
raise Exception( raise Exception(
......
...@@ -88,10 +88,12 @@ ALLOWED_EXPR_SECTIONS = [ ...@@ -88,10 +88,12 @@ ALLOWED_EXPR_SECTIONS = [
"install.files", "install.files",
] ]
ALLOWED_VARIABLES = {"os", "distro", "distro_vers", "fb", "test"}
def parse_conditional_section_name(name, section_def): def parse_conditional_section_name(name, section_def):
expr = name[len(section_def) + 1 :] expr = name[len(section_def) + 1 :]
return parse_expr(expr) return parse_expr(expr, ALLOWED_VARIABLES)
def validate_allowed_fields(file_name, section, config, allowed_fields): def validate_allowed_fields(file_name, section, config, allowed_fields):
......
...@@ -15,28 +15,38 @@ from ..expr import parse_expr ...@@ -15,28 +15,38 @@ from ..expr import parse_expr
class ExprTest(unittest.TestCase): class ExprTest(unittest.TestCase):
def test_equal(self): def test_equal(self):
e = parse_expr("foo=bar") valid_variables = {"foo", "some_var", "another_var"}
e = parse_expr("foo=bar", valid_variables)
self.assertTrue(e.eval({"foo": "bar"})) self.assertTrue(e.eval({"foo": "bar"}))
self.assertFalse(e.eval({"foo": "not-bar"})) self.assertFalse(e.eval({"foo": "not-bar"}))
self.assertFalse(e.eval({"not-foo": "bar"})) self.assertFalse(e.eval({"not-foo": "bar"}))
def test_not_equal(self): def test_not_equal(self):
e = parse_expr("not(foo=bar)") valid_variables = {"foo"}
e = parse_expr("not(foo=bar)", valid_variables)
self.assertFalse(e.eval({"foo": "bar"})) self.assertFalse(e.eval({"foo": "bar"}))
self.assertTrue(e.eval({"foo": "not-bar"})) self.assertTrue(e.eval({"foo": "not-bar"}))
def test_bad_not(self): def test_bad_not(self):
valid_variables = {"foo"}
with self.assertRaises(Exception): with self.assertRaises(Exception):
parse_expr("foo=not(bar)") parse_expr("foo=not(bar)", valid_variables)
def test_bad_variable(self):
valid_variables = {"bar"}
with self.assertRaises(Exception):
parse_expr("foo=bar", valid_variables)
def test_all(self): def test_all(self):
e = parse_expr("all(foo = bar, baz = qux)") valid_variables = {"foo", "baz"}
e = parse_expr("all(foo = bar, baz = qux)", valid_variables)
self.assertTrue(e.eval({"foo": "bar", "baz": "qux"})) self.assertTrue(e.eval({"foo": "bar", "baz": "qux"}))
self.assertFalse(e.eval({"foo": "bar", "baz": "nope"})) self.assertFalse(e.eval({"foo": "bar", "baz": "nope"}))
self.assertFalse(e.eval({"foo": "nope", "baz": "nope"})) self.assertFalse(e.eval({"foo": "nope", "baz": "nope"}))
def test_any(self): def test_any(self):
e = parse_expr("any(foo = bar, baz = qux)") valid_variables = {"foo", "baz"}
e = parse_expr("any(foo = bar, baz = qux)", valid_variables)
self.assertTrue(e.eval({"foo": "bar", "baz": "qux"})) self.assertTrue(e.eval({"foo": "bar", "baz": "qux"}))
self.assertTrue(e.eval({"foo": "bar", "baz": "nope"})) self.assertTrue(e.eval({"foo": "bar", "baz": "nope"}))
self.assertFalse(e.eval({"foo": "nope", "baz": "nope"})) self.assertFalse(e.eval({"foo": "nope", "baz": "nope"}))
...@@ -142,16 +142,16 @@ a ...@@ -142,16 +142,16 @@ a
b b
c c
[dependencies.foo=bar] [dependencies.test=on]
foo foo
""", """,
) )
self.assertEqual(p.get_section_as_args("dependencies"), ["a", "b", "c"]) self.assertEqual(p.get_section_as_args("dependencies"), ["a", "b", "c"])
self.assertEqual( self.assertEqual(
p.get_section_as_args("dependencies", {"foo": "not-bar"}), ["a", "b", "c"] p.get_section_as_args("dependencies", {"test": "off"}), ["a", "b", "c"]
) )
self.assertEqual( self.assertEqual(
p.get_section_as_args("dependencies", {"foo": "bar"}), p.get_section_as_args("dependencies", {"test": "on"}),
["a", "b", "c", "foo"], ["a", "b", "c", "foo"],
) )
...@@ -180,13 +180,13 @@ name = foo ...@@ -180,13 +180,13 @@ name = foo
[cmake.defines] [cmake.defines]
foo = bar foo = bar
[cmake.defines.bar=baz] [cmake.defines.test=on]
foo = baz foo = baz
""", """,
) )
self.assertEqual(p.get_section_as_dict("cmake.defines"), {"foo": "bar"}) self.assertEqual(p.get_section_as_dict("cmake.defines"), {"foo": "bar"})
self.assertEqual( self.assertEqual(
p.get_section_as_dict("cmake.defines", {"bar": "baz"}), {"foo": "baz"} p.get_section_as_dict("cmake.defines", {"test": "on"}), {"foo": "baz"}
) )
p2 = ManifestParser( p2 = ManifestParser(
...@@ -195,7 +195,7 @@ foo = baz ...@@ -195,7 +195,7 @@ foo = baz
[manifest] [manifest]
name = foo name = foo
[cmake.defines.bar=baz] [cmake.defines.test=on]
foo = baz foo = baz
[cmake.defines] [cmake.defines]
...@@ -203,7 +203,7 @@ foo = bar ...@@ -203,7 +203,7 @@ foo = bar
""", """,
) )
self.assertEqual( self.assertEqual(
p2.get_section_as_dict("cmake.defines", {"bar": "baz"}), p2.get_section_as_dict("cmake.defines", {"test": "on"}),
{"foo": "bar"}, {"foo": "bar"},
msg="sections cascade in the order they appear in the manifest", msg="sections cascade in the order they appear in the manifest",
) )
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment