diff options
-rw-r--r-- | mesonbuild/rewriter.py | 69 | ||||
-rwxr-xr-x | run_unittests.py | 30 | ||||
-rw-r--r-- | test cases/rewrite/1 basic/addTgt.json | 9 | ||||
-rw-r--r-- | test cases/rewrite/1 basic/info.json | 5 | ||||
-rw-r--r-- | test cases/rewrite/1 basic/rmTgt.json | 2 | ||||
-rw-r--r-- | test cases/rewrite/2 subdirs/addTgt.json | 10 | ||||
-rw-r--r-- | test cases/rewrite/2 subdirs/info.json | 5 |
7 files changed, 112 insertions, 18 deletions
diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index a3e78af..7475795 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -28,6 +28,7 @@ from mesonbuild.mesonlib import MesonException from . import mlog, mparser, environment from functools import wraps from pprint import pprint +from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseNode, IdNode, FunctionNode, StringNode import json, os class RewriterException(MesonException): @@ -251,9 +252,10 @@ rewriter_keys = { }, 'target': { 'target': (str, None, None), - 'operation': (str, None, ['src_add', 'src_rm', 'tgt_rm', 'info']), + 'operation': (str, None, ['src_add', 'src_rm', 'tgt_rm', 'tgt_add', 'info']), 'sources': (list, [], None), 'subdir': (str, '', None), + 'target_type': (str, 'executable', ['both_libraries', 'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library']), 'debug': (bool, False, None) } } @@ -456,7 +458,7 @@ class Rewriter: if num_changed > 0 and node not in self.modefied_nodes: self.modefied_nodes += [node] - def find_assignment_node(self, node: mparser.BaseNode) -> mparser.AssignmentNode: + def find_assignment_node(self, node: mparser) -> AssignmentNode: if hasattr(node, 'ast_id') and node.ast_id in self.interpreter.reverse_assignment: return self.interpreter.reverse_assignment[node.ast_id] return None @@ -465,7 +467,7 @@ class Rewriter: def process_target(self, cmd): mlog.log('Processing target', mlog.bold(cmd['target']), 'operation', mlog.cyan(cmd['operation'])) target = self.find_target(cmd['target']) - if target is None: + if target is None and cmd['operation'] != 'tgt_add': mlog.error('Unknown target "{}" --> skipping'.format(cmd['target'])) if cmd['debug']: pprint(self.interpreter.targets) @@ -476,13 +478,13 @@ class Rewriter: # Utility function to get a list of the sources from a node def arg_list_from_node(n): args = [] - if isinstance(n, mparser.FunctionNode): + if isinstance(n, FunctionNode): args = list(n.args.arguments) if n.func_name in build_target_functions: args.pop(0) - elif isinstance(n, mparser.ArrayNode): + elif isinstance(n, ArrayNode): args = n.args.arguments - elif isinstance(n, mparser.ArgumentNode): + elif isinstance(n, ArgumentNode): args = n.arguments return args @@ -499,15 +501,15 @@ class Rewriter: for i in cmd['sources']: mlog.log(' -- Adding source', mlog.green(i), 'at', mlog.yellow('{}:{}'.format(os.path.join(node.subdir, environment.build_filename), node.lineno))) - token = mparser.Token('string', node.subdir, 0, 0, 0, None, i) - to_append += [mparser.StringNode(token)] + token = Token('string', node.subdir, 0, 0, 0, None, i) + to_append += [StringNode(token)] # Append to the AST at the right place - if isinstance(node, mparser.FunctionNode): + if isinstance(node, FunctionNode): node.args.arguments += to_append - elif isinstance(node, mparser.ArrayNode): + elif isinstance(node, ArrayNode): node.args.arguments += to_append - elif isinstance(node, mparser.ArgumentNode): + elif isinstance(node, ArgumentNode): node.arguments += to_append # Mark the node as modified @@ -519,7 +521,7 @@ class Rewriter: def find_node(src): for i in target['sources']: for j in arg_list_from_node(i): - if isinstance(j, mparser.StringNode): + if isinstance(j, StringNode): if j.value == src: return i, j return None, None @@ -533,11 +535,11 @@ class Rewriter: # Remove the found string node from the argument list arg_node = None - if isinstance(root, mparser.FunctionNode): + if isinstance(root, FunctionNode): arg_node = root.args - if isinstance(root, mparser.ArrayNode): + if isinstance(root, ArrayNode): arg_node = root.args - if isinstance(root, mparser.ArgumentNode): + if isinstance(root, ArgumentNode): arg_node = root assert(arg_node is not None) mlog.log(' -- Removing source', mlog.green(i), 'from', @@ -548,6 +550,31 @@ class Rewriter: if root not in self.modefied_nodes: self.modefied_nodes += [root] + elif cmd['operation'] == 'tgt_add': + if target is not None: + mlog.error('Can not add target', mlog.bold(cmd['target']), 'because it already exists') + return + + # Build src list + src_arg_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, '')) + src_arr_node = ArrayNode(src_arg_node, 0, 0) + src_far_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, '')) + src_fun_node = FunctionNode(cmd['subdir'], 0, 0, 'files', src_far_node) + src_ass_node = AssignmentNode(cmd['subdir'], 0, 0, '{}_src'.format(cmd['target']), src_fun_node) + src_arg_node.arguments = [StringNode(Token('string', cmd['subdir'], 0, 0, 0, None, x)) for x in cmd['sources']] + src_far_node.arguments = [src_arr_node] + + # Build target + tgt_arg_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, '')) + tgt_fun_node = FunctionNode(cmd['subdir'], 0, 0, cmd['target_type'], tgt_arg_node) + tgt_ass_node = AssignmentNode(cmd['subdir'], 0, 0, '{}_tgt'.format(cmd['target']), tgt_fun_node) + tgt_arg_node.arguments = [ + StringNode(Token('string', cmd['subdir'], 0, 0, 0, None, cmd['target'])), + IdNode(Token('string', cmd['subdir'], 0, 0, 0, None, '{}_src'.format(cmd['target']))) + ] + + self.to_add_nodes += [src_ass_node, tgt_ass_node] + elif cmd['operation'] == 'tgt_rm': to_remove = self.find_assignment_node(target['node']) if to_remove is None: @@ -586,12 +613,13 @@ class Rewriter: work_nodes = [{'node': x, 'action': 'modify'} for x in self.modefied_nodes] work_nodes += [{'node': x, 'action': 'rm'} for x in self.to_remove_nodes] work_nodes = list(sorted(work_nodes, key=lambda x: x['node'].lineno * 1000 + x['node'].colno, reverse=True)) + work_nodes += [{'node': x, 'action': 'add'} for x in self.to_add_nodes] # Generating the new replacement string str_list = [] for i in work_nodes: new_data = '' - if i['action'] == 'modify': + if i['action'] == 'modify' or i['action'] == 'add': printer = AstPrinter() i['node'].accept(printer) printer.post_process() @@ -611,6 +639,10 @@ class Rewriter: continue fpath = os.path.realpath(os.path.join(self.sourcedir, i['file'])) fdata = '' + # Create an empty file if it does not exist + if not os.path.exists(fpath): + with open(fpath, 'w'): + pass with open(fpath, 'r') as fp: fdata = fp.read() @@ -677,7 +709,10 @@ class Rewriter: raw = files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:] for i in str_list: - remove_node(i) + if i['action'] in ['modify', 'rm']: + remove_node(i) + elif i['action'] in ['add']: + files[i['file']]['raw'] += i['str'] + '\n' # Write the files back for key, val in files.items(): diff --git a/run_unittests.py b/run_unittests.py index a0b3ed5..aeb56c6 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5180,6 +5180,28 @@ class RewriterTests(BasePlatformTests): } self.assertDictEqual(out, expected) + def test_tatrget_add(self): + self.prime('1 basic') + self.rewrite(self.builddir, os.path.join(self.builddir, 'addTgt.json')) + out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json')) + out = self.extract_test_data(out) + + expected = { + 'target': { + 'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['fileB.cpp', 'fileC.cpp']}, + 'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['main.cpp', 'fileB.cpp', 'fileC.cpp']}, + 'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileB.cpp', 'fileC.cpp', 'main.cpp', 'fileA.cpp']}, + 'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog9@exe': {'name': 'trivialprog9', 'sources': ['main.cpp', 'fileA.cpp']}, + 'trivialprog10@sha': {'name': 'trivialprog10', 'sources': ['new1.cpp', 'new2.cpp']}, + } + } + self.assertDictEqual(out, expected) + def test_target_remove_subdir(self): self.prime('2 subdirs') self.rewrite(self.builddir, os.path.join(self.builddir, 'rmTgt.json')) @@ -5187,6 +5209,14 @@ class RewriterTests(BasePlatformTests): out = self.extract_test_data(out) self.assertDictEqual(out, {}) + def test_tatrget_add_subdir(self): + self.prime('2 subdirs') + self.rewrite(self.builddir, os.path.join(self.builddir, 'addTgt.json')) + out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json')) + out = self.extract_test_data(out) + expected = {'name': 'something', 'sources': ['first.c', 'second.c']} + self.assertDictEqual(list(out['target'].values())[0], expected) + def test_kwargs_info(self): self.prime('3 kwargs') out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json')) diff --git a/test cases/rewrite/1 basic/addTgt.json b/test cases/rewrite/1 basic/addTgt.json new file mode 100644 index 0000000..432e299 --- /dev/null +++ b/test cases/rewrite/1 basic/addTgt.json @@ -0,0 +1,9 @@ +[ + { + "type": "target", + "target": "trivialprog10", + "operation": "tgt_add", + "sources": ["new1.cpp", "new2.cpp"], + "target_type": "shared_library" + } +] diff --git a/test cases/rewrite/1 basic/info.json b/test cases/rewrite/1 basic/info.json index c791c8f..7e44bec 100644 --- a/test cases/rewrite/1 basic/info.json +++ b/test cases/rewrite/1 basic/info.json @@ -43,5 +43,10 @@ "type": "target", "target": "trivialprog9", "operation": "info" + }, + { + "type": "target", + "target": "trivialprog10", + "operation": "info" } ] diff --git a/test cases/rewrite/1 basic/rmTgt.json b/test cases/rewrite/1 basic/rmTgt.json index 9172296..ac3f3a2 100644 --- a/test cases/rewrite/1 basic/rmTgt.json +++ b/test cases/rewrite/1 basic/rmTgt.json @@ -9,4 +9,4 @@ "target": "trivialprog9", "operation": "tgt_rm" } -]
\ No newline at end of file +] diff --git a/test cases/rewrite/2 subdirs/addTgt.json b/test cases/rewrite/2 subdirs/addTgt.json new file mode 100644 index 0000000..01e9a6e --- /dev/null +++ b/test cases/rewrite/2 subdirs/addTgt.json @@ -0,0 +1,10 @@ +[ + { + "type": "target", + "target": "newLib", + "operation": "tgt_add", + "sources": ["new1.cpp", "new2.cpp"], + "target_type": "shared_library", + "subdir": "sub2" + } +] diff --git a/test cases/rewrite/2 subdirs/info.json b/test cases/rewrite/2 subdirs/info.json index 7075fa8..dba2cd6 100644 --- a/test cases/rewrite/2 subdirs/info.json +++ b/test cases/rewrite/2 subdirs/info.json @@ -3,5 +3,10 @@ "type": "target", "target": "something", "operation": "info" + }, + { + "type": "target", + "target": "newLib", + "operation": "info" } ] |