aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/rewriter.py99
-rwxr-xr-xrun_unittests.py42
-rw-r--r--test cases/rewrite/3 kwargs/defopts_delete.json18
-rw-r--r--test cases/rewrite/3 kwargs/defopts_set.json24
-rw-r--r--test cases/rewrite/3 kwargs/remove_regex.json20
5 files changed, 192 insertions, 11 deletions
diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py
index fa26571..f5f8b61 100644
--- a/mesonbuild/rewriter.py
+++ b/mesonbuild/rewriter.py
@@ -29,7 +29,7 @@ from . import mlog, mparser, environment
from functools import wraps
from pprint import pprint
from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, IdNode, FunctionNode, StringNode
-import json, os
+import json, os, re
class RewriterException(MesonException):
pass
@@ -109,6 +109,10 @@ class MTypeBase:
# Overwrite in derived class
mlog.warning('Cannot remove a value of type', mlog.bold(type(self).__name__), '--> skipping')
+ def remove_regex(self, value):
+ # Overwrite in derived class
+ mlog.warning('Cannot remove a regex in type', mlog.bold(type(self).__name__), '--> skipping')
+
class MTypeStr(MTypeBase):
def __init__(self, node: mparser.BaseNode):
super().__init__(node)
@@ -165,7 +169,11 @@ class MTypeList(MTypeBase):
self.node = self._new_node()
self.node.args.arguments += [tmp]
- def _check_is_equal(self, node, value):
+ def _check_is_equal(self, node, value) -> bool:
+ # Overwrite in derived class
+ return False
+
+ def _check_regex_matches(self, node, regex: str) -> bool:
# Overwrite in derived class
return False
@@ -197,10 +205,10 @@ class MTypeList(MTypeBase):
for i in value:
self.node.args.arguments += [self._new_element_node(i)]
- def remove_value(self, value):
+ def _remove_helper(self, value, equal_func):
def check_remove_node(node):
for j in value:
- if self._check_is_equal(i, j):
+ if equal_func(i, j):
return True
return False
@@ -213,18 +221,29 @@ class MTypeList(MTypeBase):
removed_list += [i]
self.node.args.arguments = removed_list
-class MtypeStrList(MTypeList):
+ def remove_value(self, value):
+ self._remove_helper(value, self._check_is_equal)
+
+ def remove_regex(self, regex: str):
+ self._remove_helper(regex, self._check_regex_matches)
+
+class MTypeStrList(MTypeList):
def __init__(self, node: mparser.BaseNode):
super().__init__(node)
def _new_element_node(self, value):
return mparser.StringNode(mparser.Token('', '', 0, 0, 0, None, str(value)))
- def _check_is_equal(self, node, value):
+ def _check_is_equal(self, node, value) -> bool:
if isinstance(node, mparser.StringNode):
return node.value == value
return False
+ def _check_regex_matches(self, node, regex: str) -> bool:
+ if isinstance(node, mparser.StringNode):
+ return re.match(regex, node.value) is not None
+ return False
+
def supported_element_nodes(self):
return [mparser.StringNode]
@@ -235,19 +254,28 @@ class MTypeIDList(MTypeList):
def _new_element_node(self, value):
return mparser.IdNode(mparser.Token('', '', 0, 0, 0, None, str(value)))
- def _check_is_equal(self, node, value):
+ def _check_is_equal(self, node, value) -> bool:
if isinstance(node, mparser.IdNode):
return node.value == value
return False
+ def _check_regex_matches(self, node, regex: str) -> bool:
+ if isinstance(node, mparser.StringNode):
+ return re.match(regex, node.value) is not None
+ return False
+
def supported_element_nodes(self):
return [mparser.IdNode]
rewriter_keys = {
+ 'default_options': {
+ 'operation': (str, None, ['set', 'delete']),
+ 'options': (dict, {}, None)
+ },
'kwargs': {
'function': (str, None, None),
'id': (str, None, None),
- 'operation': (str, None, ['set', 'delete', 'add', 'remove', 'info']),
+ 'operation': (str, None, ['set', 'delete', 'add', 'remove', 'remove_regex', 'info']),
'kwargs': (dict, {}, None)
},
'target': {
@@ -268,8 +296,8 @@ rewriter_func_kwargs = {
'not_found_message': MTypeStr,
'required': MTypeBool,
'static': MTypeBool,
- 'version': MtypeStrList,
- 'modules': MtypeStrList
+ 'version': MTypeStrList,
+ 'modules': MTypeStrList
},
'target': {
'build_by_default': MTypeBool,
@@ -285,8 +313,9 @@ rewriter_func_kwargs = {
'pie': MTypeBool
},
'project': {
+ 'default_options': MTypeStrList,
'meson_version': MTypeStr,
- 'license': MtypeStrList,
+ 'license': MTypeStrList,
'subproject_dir': MTypeStr,
'version': MTypeStr
}
@@ -300,6 +329,7 @@ class Rewriter:
self.to_remove_nodes = []
self.to_add_nodes = []
self.functions = {
+ 'default_options': self.process_default_options,
'kwargs': self.process_kwargs,
'target': self.process_target,
}
@@ -368,6 +398,50 @@ class Rewriter:
return dep
+ @RequiredKeys(rewriter_keys['default_options'])
+ def process_default_options(self, cmd):
+ # First, remove the old values
+ kwargs_cmd = {
+ 'function': 'project',
+ 'id': "",
+ 'operation': 'remove_regex',
+ 'kwargs': {
+ 'default_options': ['{}=.*'.format(x) for x in cmd['options'].keys()]
+ }
+ }
+ self.process_kwargs(kwargs_cmd)
+
+ # Then add the new values
+ if cmd['operation'] != 'set':
+ return
+
+ kwargs_cmd['operation'] = 'add'
+ kwargs_cmd['kwargs']['default_options'] = []
+
+ cdata = self.interpreter.coredata
+ options = {
+ **cdata.builtins,
+ **cdata.backend_options,
+ **cdata.base_options,
+ **cdata.compiler_options.build,
+ **cdata.user_options
+ }
+
+ for key, val in cmd['options'].items():
+ if key not in options:
+ mlog.error('Unknown options', mlog.bold(key), '--> skipping')
+ continue
+
+ try:
+ val = options[key].validate_value(val)
+ except MesonException as e:
+ mlog.error('Unable to set', mlog.bold(key), mlog.red(str(e)), '--> skipping')
+ continue
+
+ kwargs_cmd['kwargs']['default_options'] += ['{}={}'.format(key, val)]
+
+ self.process_kwargs(kwargs_cmd)
+
@RequiredKeys(rewriter_keys['kwargs'])
def process_kwargs(self, cmd):
mlog.log('Processing function type', mlog.bold(cmd['function']), 'with id', mlog.cyan("'" + cmd['id'] + "'"))
@@ -450,6 +524,9 @@ class Rewriter:
elif cmd['operation'] == 'remove':
mlog.log(' -- Removing', mlog.yellow(val_str), 'from', mlog.bold(key))
modifyer.remove_value(val)
+ elif cmd['operation'] == 'remove_regex':
+ mlog.log(' -- Removing all values matching', mlog.yellow(val_str), 'from', mlog.bold(key))
+ modifyer.remove_regex(val)
# Write back the result
arg_node.kwargs[key] = modifyer.get_node()
diff --git a/run_unittests.py b/run_unittests.py
index fee8077..cf6c910 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -5310,6 +5310,20 @@ class RewriterTests(BasePlatformTests):
}
self.assertDictEqual(out, expected)
+ def test_kwargs_remove_regex(self):
+ self.prime('3 kwargs')
+ self.rewrite(self.builddir, os.path.join(self.builddir, 'remove_regex.json'))
+ out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
+ out = self.extract_test_data(out)
+ expected = {
+ 'kwargs': {
+ 'project#': {'version': '0.0.1', 'default_options': ['buildtype=release', 'debug=true']},
+ 'target#tgt1': {'build_by_default': True},
+ 'dependency#dep1': {'required': False}
+ }
+ }
+ self.assertDictEqual(out, expected)
+
def test_kwargs_delete(self):
self.prime('3 kwargs')
self.rewrite(self.builddir, os.path.join(self.builddir, 'delete.json'))
@@ -5324,6 +5338,34 @@ class RewriterTests(BasePlatformTests):
}
self.assertDictEqual(out, expected)
+ def test_default_options_set(self):
+ self.prime('3 kwargs')
+ self.rewrite(self.builddir, os.path.join(self.builddir, 'defopts_set.json'))
+ out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
+ out = self.extract_test_data(out)
+ expected = {
+ 'kwargs': {
+ 'project#': {'version': '0.0.1', 'default_options': ['buildtype=release', 'debug=True', 'cpp_std=c++11']},
+ 'target#tgt1': {'build_by_default': True},
+ 'dependency#dep1': {'required': False}
+ }
+ }
+ self.assertDictEqual(out, expected)
+
+ def test_default_options_delete(self):
+ self.prime('3 kwargs')
+ self.rewrite(self.builddir, os.path.join(self.builddir, 'defopts_delete.json'))
+ out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
+ out = self.extract_test_data(out)
+ expected = {
+ 'kwargs': {
+ 'project#': {'version': '0.0.1', 'default_options': ['cpp_std=c++14', 'debug=true']},
+ 'target#tgt1': {'build_by_default': True},
+ 'dependency#dep1': {'required': False}
+ }
+ }
+ self.assertDictEqual(out, expected)
+
class NativeFileTests(BasePlatformTests):
def setUp(self):
diff --git a/test cases/rewrite/3 kwargs/defopts_delete.json b/test cases/rewrite/3 kwargs/defopts_delete.json
new file mode 100644
index 0000000..06232dd
--- /dev/null
+++ b/test cases/rewrite/3 kwargs/defopts_delete.json
@@ -0,0 +1,18 @@
+[
+ {
+ "type": "kwargs",
+ "function": "project",
+ "id": "",
+ "operation": "set",
+ "kwargs": {
+ "default_options": ["cpp_std=c++14", "buildtype=release", "debug=true"]
+ }
+ },
+ {
+ "type": "default_options",
+ "operation": "delete",
+ "options": {
+ "buildtype": null
+ }
+ }
+]
diff --git a/test cases/rewrite/3 kwargs/defopts_set.json b/test cases/rewrite/3 kwargs/defopts_set.json
new file mode 100644
index 0000000..f8f855f
--- /dev/null
+++ b/test cases/rewrite/3 kwargs/defopts_set.json
@@ -0,0 +1,24 @@
+[
+ {
+ "type": "default_options",
+ "operation": "set",
+ "options": {
+ "cpp_std": "c++14"
+ }
+ },
+ {
+ "type": "default_options",
+ "operation": "set",
+ "options": {
+ "buildtype": "release",
+ "debug": true
+ }
+ },
+ {
+ "type": "default_options",
+ "operation": "set",
+ "options": {
+ "cpp_std": "c++11"
+ }
+ }
+]
diff --git a/test cases/rewrite/3 kwargs/remove_regex.json b/test cases/rewrite/3 kwargs/remove_regex.json
new file mode 100644
index 0000000..fcb04eb
--- /dev/null
+++ b/test cases/rewrite/3 kwargs/remove_regex.json
@@ -0,0 +1,20 @@
+[
+ {
+ "type": "kwargs",
+ "function": "project",
+ "id": "",
+ "operation": "set",
+ "kwargs": {
+ "default_options": ["cpp_std=c++14", "buildtype=release", "debug=true"]
+ }
+ },
+ {
+ "type": "kwargs",
+ "function": "project",
+ "id": "",
+ "operation": "remove_regex",
+ "kwargs": {
+ "default_options": ["cpp_std=.*"]
+ }
+ }
+]