diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2020-03-01 18:17:41 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-01 18:17:41 +0200 |
commit | 25cbcb19a9208ebf8f5cde3f8ecb91df0a2dfebf (patch) | |
tree | cf29f0c60ac4014b9395edbe2a9c3efdad449291 | |
parent | 74452f2a1c842291c893504876507946103ac77f (diff) | |
parent | 96f661e15046a4222fd01a7216e18de901b73cb6 (diff) | |
download | meson-25cbcb19a9208ebf8f5cde3f8ecb91df0a2dfebf.zip meson-25cbcb19a9208ebf8f5cde3f8ecb91df0a2dfebf.tar.gz meson-25cbcb19a9208ebf8f5cde3f8ecb91df0a2dfebf.tar.bz2 |
Merge pull request #6627 from jon-turney/cwd-relative-file-locations
Consistently report file locations relative to cwd
-rw-r--r-- | docs/markdown/snippets/consistent_file_locations.md | 9 | ||||
-rw-r--r-- | mesonbuild/ast/interpreter.py | 4 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 4 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 4 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 17 | ||||
-rw-r--r-- | mesonbuild/mlog.py | 16 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 70 | ||||
-rw-r--r-- | mesonbuild/optinterpreter.py | 7 | ||||
-rw-r--r-- | mesonbuild/rewriter.py | 35 | ||||
-rwxr-xr-x | run_unittests.py | 51 | ||||
-rw-r--r-- | test cases/failing/100 subdir parse error/meson.build | 2 | ||||
-rw-r--r-- | test cases/failing/100 subdir parse error/subdir/meson.build | 1 | ||||
-rw-r--r-- | test cases/failing/101 invalid option file/meson.build | 1 | ||||
-rw-r--r-- | test cases/failing/101 invalid option file/meson_options.txt | 1 |
14 files changed, 137 insertions, 85 deletions
diff --git a/docs/markdown/snippets/consistent_file_locations.md b/docs/markdown/snippets/consistent_file_locations.md new file mode 100644 index 0000000..5f384fe --- /dev/null +++ b/docs/markdown/snippets/consistent_file_locations.md @@ -0,0 +1,9 @@ +## Consistently report file locations relative to cwd + +The paths for filenames in error and warning locations are now consistently +reported relative to the current working directory (when possible), or as +absolute paths (when a relative path does not exist, e.g. a Windows path +starting with a different drive letter to the current working directory). + +(The previous behaviour was to report a path relative to the source root for all +warnings and most errors, and relative to cwd for certain parser errors) diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index b5aade3..5f47ad3 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -154,9 +154,9 @@ class AstInterpreter(interpreterbase.InterpreterBase): code = f.read() assert(isinstance(code, str)) try: - codeblock = mparser.Parser(code, subdir).parse() + codeblock = mparser.Parser(code, absname).parse() except mesonlib.MesonException as me: - me.file = buildfilename + me.file = absname raise me self.subdir = subdir diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c29ed89..a9e0a3b 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3748,9 +3748,9 @@ This will become a hard error in the future.''' % kwargs['input'], location=self code = f.read() assert(isinstance(code, str)) try: - codeblock = mparser.Parser(code, self.subdir).parse() + codeblock = mparser.Parser(code, absname).parse() except mesonlib.MesonException as me: - me.file = buildfilename + me.file = absname raise me try: self.evaluate_codeblock(codeblock) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 2a976d3..d723da5 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -381,7 +381,7 @@ class InterpreterBase: raise InvalidCode('Builder file is empty.') assert(isinstance(code, str)) try: - self.ast = mparser.Parser(code, self.subdir).parse() + self.ast = mparser.Parser(code, mesonfile).parse() except mesonlib.MesonException as me: me.file = mesonfile raise me @@ -432,7 +432,7 @@ class InterpreterBase: if not hasattr(e, 'lineno'): e.lineno = cur.lineno e.colno = cur.colno - e.file = os.path.join(self.subdir, 'meson.build') + e.file = os.path.join(self.source_root, self.subdir, environment.build_filename) raise e i += 1 # In THE FUTURE jump over blocks and stuff. diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index e09d123..854c934 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -122,13 +122,6 @@ an_unpicklable_object = threading.Lock() class MesonException(Exception): '''Exceptions thrown by Meson''' - def get_msg_with_context(self): - s = '' - if hasattr(self, 'lineno') and hasattr(self, 'file'): - s = get_error_location_string(self.file, self.lineno) + ' ' - s += str(self) - return s - class EnvironmentException(MesonException): '''Exceptions thrown while processing and creating the build environment''' @@ -1339,16 +1332,6 @@ def detect_subprojects(spdir_name, current_dir='', result=None): result[basename] = [trial] return result -# This isn't strictly correct. What we really want here is something like: -# class StringProtocol(typing_extensions.Protocol): -# -# def __str__(self) -> str: ... -# -# This would more accurately embody what this funcitonc an handle, but we -# don't have that yet, so instead we'll do some casting to work around it -def get_error_location_string(fname: str, lineno: str) -> str: - return '{}:{}:'.format(fname, lineno) - def substring_is_in_list(substr: str, strlist: T.List[str]) -> bool: for s in strlist: if substr in s: diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index 64c16f5..a1acfa3 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -221,11 +221,19 @@ def log_once(*args: T.Union[str, AnsiDecorator], is_error: bool = False, _logged_once.add(t) log(*args, is_error=is_error, **kwargs) +# This isn't strictly correct. What we really want here is something like: +# class StringProtocol(typing_extensions.Protocol): +# +# def __str__(self) -> str: ... +# +# This would more accurately embody what this function can handle, but we +# don't have that yet, so instead we'll do some casting to work around it +def get_error_location_string(fname: str, lineno: str) -> str: + return '{}:{}:'.format(fname, lineno) + def _log_error(severity: str, *rargs: T.Union[str, AnsiDecorator], once: bool = False, **kwargs: T.Any) -> None: - from .mesonlib import get_error_location_string - from .environment import build_filename - from .mesonlib import MesonException + from .mesonlib import MesonException, relpath # The typing requirements here are non-obvious. Lists are invariant, # therefore T.List[A] and T.List[T.Union[A, B]] are not able to be joined @@ -242,7 +250,7 @@ def _log_error(severity: str, *rargs: T.Union[str, AnsiDecorator], location = kwargs.pop('location', None) if location is not None: - location_file = os.path.join(location.subdir, build_filename) + location_file = relpath(location.filename, os.getcwd()) location_str = get_error_location_string(location_file, location.lineno) # Unions are frankly awful, and we have to T.cast here to get mypy # to understand that the list concatenation is safe diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 2b503f1..430c89e 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -72,9 +72,9 @@ class BlockParseException(MesonException): self.colno = colno class Token: - def __init__(self, tid, subdir, line_start, lineno, colno, bytespan, value): + def __init__(self, tid, filename, line_start, lineno, colno, bytespan, value): self.tid = tid - self.subdir = subdir + self.filename = filename self.line_start = line_start self.lineno = lineno self.colno = colno @@ -132,7 +132,7 @@ class Lexer: def getline(self, line_start): return self.code[line_start:self.code.find('\n', line_start)] - def lex(self, subdir): + def lex(self, filename): line_start = 0 lineno = 1 loc = 0 @@ -205,9 +205,9 @@ This will become a hard error in a future Meson release.""", self.getline(line_s else: if match_text in self.future_keywords: mlog.warning("Identifier '{}' will become a reserved keyword in a future release. Please rename it.".format(match_text), - location=types.SimpleNamespace(subdir=subdir, lineno=lineno)) + location=types.SimpleNamespace(filename=filename, lineno=lineno)) value = match_text - yield Token(tid, subdir, curline_start, curline, col, bytespan, value) + yield Token(tid, filename, curline_start, curline, col, bytespan, value) break if not matched: raise ParseException('lexer', self.getline(line_start), lineno, col) @@ -223,7 +223,7 @@ class BaseNode: class ElementaryNode(BaseNode): def __init__(self, token): self.lineno = token.lineno - self.subdir = token.subdir + self.filename = token.filename self.colno = token.colno self.value = token.value self.bytespan = token.bytespan @@ -263,7 +263,7 @@ class BreakNode(ElementaryNode): class ArrayNode(BaseNode): def __init__(self, args, lineno, colno, end_lineno, end_colno): - self.subdir = args.subdir + self.filename = args.filename self.lineno = lineno self.colno = colno self.end_lineno = end_lineno @@ -272,7 +272,7 @@ class ArrayNode(BaseNode): class DictNode(BaseNode): def __init__(self, args, lineno, colno, end_lineno, end_colno): - self.subdir = args.subdir + self.filename = args.filename self.lineno = lineno self.colno = colno self.end_lineno = end_lineno @@ -281,14 +281,14 @@ class DictNode(BaseNode): class EmptyNode(BaseNode): def __init__(self, lineno, colno): - self.subdir = '' + self.filename = '' self.lineno = lineno self.colno = colno self.value = None class OrNode(BaseNode): def __init__(self, left, right): - self.subdir = left.subdir + self.filename = left.filename self.lineno = left.lineno self.colno = left.colno self.left = left @@ -296,7 +296,7 @@ class OrNode(BaseNode): class AndNode(BaseNode): def __init__(self, left, right): - self.subdir = left.subdir + self.filename = left.filename self.lineno = left.lineno self.colno = left.colno self.left = left @@ -306,14 +306,14 @@ class ComparisonNode(BaseNode): def __init__(self, ctype, left, right): self.lineno = left.lineno self.colno = left.colno - self.subdir = left.subdir + self.filename = left.filename self.left = left self.right = right self.ctype = ctype class ArithmeticNode(BaseNode): def __init__(self, operation, left, right): - self.subdir = left.subdir + self.filename = left.filename self.lineno = left.lineno self.colno = left.colno self.left = left @@ -322,14 +322,14 @@ class ArithmeticNode(BaseNode): class NotNode(BaseNode): def __init__(self, location_node, value): - self.subdir = location_node.subdir + self.filename = location_node.filename self.lineno = location_node.lineno self.colno = location_node.colno self.value = value class CodeBlockNode(BaseNode): def __init__(self, location_node): - self.subdir = location_node.subdir + self.filename = location_node.filename self.lineno = location_node.lineno self.colno = location_node.colno self.lines = [] @@ -338,13 +338,13 @@ class IndexNode(BaseNode): def __init__(self, iobject, index): self.iobject = iobject self.index = index - self.subdir = iobject.subdir + self.filename = iobject.filename self.lineno = iobject.lineno self.colno = iobject.colno class MethodNode(BaseNode): - def __init__(self, subdir, lineno, colno, source_object, name, args): - self.subdir = subdir + def __init__(self, filename, lineno, colno, source_object, name, args): + self.filename = filename self.lineno = lineno self.colno = colno self.source_object = source_object @@ -353,8 +353,8 @@ class MethodNode(BaseNode): self.args = args class FunctionNode(BaseNode): - def __init__(self, subdir, lineno, colno, end_lineno, end_colno, func_name, args): - self.subdir = subdir + def __init__(self, filename, lineno, colno, end_lineno, end_colno, func_name, args): + self.filename = filename self.lineno = lineno self.colno = colno self.end_lineno = end_lineno @@ -364,8 +364,8 @@ class FunctionNode(BaseNode): self.args = args class AssignmentNode(BaseNode): - def __init__(self, subdir, lineno, colno, var_name, value): - self.subdir = subdir + def __init__(self, filename, lineno, colno, var_name, value): + self.filename = filename self.lineno = lineno self.colno = colno self.var_name = var_name @@ -373,8 +373,8 @@ class AssignmentNode(BaseNode): self.value = value class PlusAssignmentNode(BaseNode): - def __init__(self, subdir, lineno, colno, var_name, value): - self.subdir = subdir + def __init__(self, filename, lineno, colno, var_name, value): + self.filename = filename self.lineno = lineno self.colno = colno self.var_name = var_name @@ -398,7 +398,7 @@ class IfClauseNode(BaseNode): class UMinusNode(BaseNode): def __init__(self, current_location, value): - self.subdir = current_location.subdir + self.filename = current_location.filename self.lineno = current_location.lineno self.colno = current_location.colno self.value = value @@ -411,8 +411,8 @@ class IfNode(BaseNode): self.block = block class TernaryNode(BaseNode): - def __init__(self, subdir, lineno, colno, condition, trueblock, falseblock): - self.subdir = subdir + def __init__(self, filename, lineno, colno, condition, trueblock, falseblock): + self.filename = filename self.lineno = lineno self.colno = colno self.condition = condition @@ -423,7 +423,7 @@ class ArgumentNode(BaseNode): def __init__(self, token): self.lineno = token.lineno self.colno = token.colno - self.subdir = token.subdir + self.filename = token.filename self.arguments = [] self.commas = [] self.kwargs = {} @@ -485,9 +485,9 @@ comparison_map = {'equal': '==', # 9 plain token class Parser: - def __init__(self, code, subdir): + def __init__(self, code, filename): self.lexer = Lexer(code) - self.stream = self.lexer.lex(subdir) + self.stream = self.lexer.lex(filename) self.current = Token('eof', '', 0, 0, 0, (0, 0), None) self.getsym() self.in_ternary = False @@ -531,13 +531,13 @@ class Parser: value = self.e1() if not isinstance(left, IdNode): raise ParseException('Plusassignment target must be an id.', self.getline(), left.lineno, left.colno) - return PlusAssignmentNode(left.subdir, left.lineno, left.colno, left.value, value) + return PlusAssignmentNode(left.filename, left.lineno, left.colno, left.value, value) elif self.accept('assign'): value = self.e1() if not isinstance(left, IdNode): raise ParseException('Assignment target must be an id.', self.getline(), left.lineno, left.colno) - return AssignmentNode(left.subdir, left.lineno, left.colno, left.value, value) + return AssignmentNode(left.filename, left.lineno, left.colno, left.value, value) elif self.accept('questionmark'): if self.in_ternary: raise ParseException('Nested ternary operators are not allowed.', @@ -547,7 +547,7 @@ class Parser: self.expect('colon') falseblock = self.e1() self.in_ternary = False - return TernaryNode(left.subdir, left.lineno, left.colno, left, trueblock, falseblock) + return TernaryNode(left.filename, left.lineno, left.colno, left, trueblock, falseblock) return left def e2(self): @@ -626,7 +626,7 @@ class Parser: if not isinstance(left, IdNode): raise ParseException('Function call must be applied to plain id', self.getline(), left.lineno, left.colno) - left = FunctionNode(left.subdir, left.lineno, left.colno, self.current.lineno, self.current.colno, left.value, args) + left = FunctionNode(left.filename, left.lineno, left.colno, self.current.lineno, self.current.colno, left.value, args) go_again = True while go_again: go_again = False @@ -718,7 +718,7 @@ class Parser: self.expect('lparen') args = self.args() self.expect('rparen') - method = MethodNode(methodname.subdir, methodname.lineno, methodname.colno, source_object, methodname.value, args) + method = MethodNode(methodname.filename, methodname.lineno, methodname.colno, source_object, methodname.value, args) if self.accept('dot'): return self.method_call(method) return method diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 1a8a04a..fd0a8c9 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os, re +import re import functools import typing as T @@ -140,13 +140,14 @@ class OptionInterpreter: def process(self, option_file): try: with open(option_file, 'r', encoding='utf8') as f: - ast = mparser.Parser(f.read(), '').parse() + ast = mparser.Parser(f.read(), option_file).parse() except mesonlib.MesonException as me: me.file = option_file raise me if not isinstance(ast, mparser.CodeBlockNode): e = OptionException('Option file is malformed.') e.lineno = ast.lineno() + e.file = option_file raise e for cur in ast.lines: try: @@ -154,7 +155,7 @@ class OptionInterpreter: except Exception as e: e.lineno = cur.lineno e.colno = cur.colno - e.file = os.path.join('meson_options.txt') + e.file = option_file raise e def reduce_single(self, arg): diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index b634d00..39d8337 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -651,8 +651,8 @@ class Rewriter: mlog.log(' -- Source', mlog.green(i), 'is already defined for the target --> skipping') continue mlog.log(' -- Adding source', mlog.green(i), 'at', - mlog.yellow('{}:{}'.format(os.path.join(node.subdir, environment.build_filename), node.lineno))) - token = Token('string', node.subdir, 0, 0, 0, None, i) + mlog.yellow('{}:{}'.format(node.filename, node.lineno))) + token = Token('string', node.filename, 0, 0, 0, None, i) to_append += [StringNode(token)] # Append to the AST at the right place @@ -695,7 +695,7 @@ class Rewriter: arg_node = root assert(arg_node is not None) mlog.log(' -- Removing source', mlog.green(i), 'from', - mlog.yellow('{}:{}'.format(os.path.join(string_node.subdir, environment.build_filename), string_node.lineno))) + mlog.yellow('{}:{}'.format(string_node.filename, string_node.lineno))) arg_node.arguments.remove(string_node) # Mark the node as modified @@ -712,23 +712,24 @@ class Rewriter: id_base = re.sub(r'[- ]', '_', cmd['target']) target_id = id_base + '_exe' if cmd['target_type'] == 'executable' else '_lib' source_id = id_base + '_sources' + filename = os.path.join(cmd['subdir'], environment.build_filename) # Build src list - src_arg_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, '')) + src_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, '')) src_arr_node = ArrayNode(src_arg_node, 0, 0, 0, 0) - src_far_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, '')) - src_fun_node = FunctionNode(cmd['subdir'], 0, 0, 0, 0, 'files', src_far_node) - src_ass_node = AssignmentNode(cmd['subdir'], 0, 0, source_id, 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 = ArgumentNode(Token('string', filename, 0, 0, 0, None, '')) + src_fun_node = FunctionNode(filename, 0, 0, 0, 0, 'files', src_far_node) + src_ass_node = AssignmentNode(filename, 0, 0, source_id, src_fun_node) + src_arg_node.arguments = [StringNode(Token('string', filename, 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, 0, 0, cmd['target_type'], tgt_arg_node) - tgt_ass_node = AssignmentNode(cmd['subdir'], 0, 0, target_id, tgt_fun_node) + tgt_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, '')) + tgt_fun_node = FunctionNode(filename, 0, 0, 0, 0, cmd['target_type'], tgt_arg_node) + tgt_ass_node = AssignmentNode(filename, 0, 0, target_id, 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, source_id)) + StringNode(Token('string', filename, 0, 0, 0, None, cmd['target'])), + IdNode(Token('string', filename, 0, 0, 0, None, source_id)) ] src_ass_node.accept(AstIndentationGenerator()) @@ -741,7 +742,7 @@ class Rewriter: to_remove = target['node'] self.to_remove_nodes += [to_remove] mlog.log(' -- Removing target', mlog.green(cmd['target']), 'at', - mlog.yellow('{}:{}'.format(os.path.join(to_remove.subdir, environment.build_filename), to_remove.lineno))) + mlog.yellow('{}:{}'.format(to_remove.filename, to_remove.lineno))) elif cmd['operation'] == 'info': # T.List all sources in the target @@ -776,8 +777,8 @@ class Rewriter: self.functions[cmd['type']](cmd) def apply_changes(self): - assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'subdir') for x in self.modefied_nodes)) - assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'subdir') for x in self.to_remove_nodes)) + assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.modefied_nodes)) + assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.to_remove_nodes)) assert(all(isinstance(x, (ArrayNode, FunctionNode)) for x in self.modefied_nodes)) assert(all(isinstance(x, (ArrayNode, AssignmentNode, FunctionNode)) for x in self.to_remove_nodes)) # Sort based on line and column in reversed order @@ -796,7 +797,7 @@ class Rewriter: printer.post_process() new_data = printer.result.strip() data = { - 'file': os.path.join(i['node'].subdir, environment.build_filename), + 'file': i['node'].filename, 'str': new_data, 'node': i['node'], 'action': i['action'] diff --git a/run_unittests.py b/run_unittests.py index 0861f59..d091cbc 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -56,7 +56,7 @@ from mesonbuild.mesonlib import ( BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos, windows_proof_rmtree, python_command, version_compare, split_args, - quote_arg + quote_arg, relpath ) from mesonbuild.environment import detect_ninja from mesonbuild.mesonlib import MesonException, EnvironmentException @@ -1512,7 +1512,8 @@ class BasePlatformTests(unittest.TestCase): extra_args=None, default_args=True, inprocess=False, - override_envvars=None): + override_envvars=None, + workdir=None): self.assertPathExists(srcdir) if extra_args is None: extra_args = [] @@ -1553,7 +1554,7 @@ class BasePlatformTests(unittest.TestCase): mesonbuild.mlog.log_file = None else: try: - out = self._run(self.setup_command + args + extra_args, override_envvars=override_envvars) + out = self._run(self.setup_command + args + extra_args, override_envvars=override_envvars, workdir=workdir) except unittest.SkipTest: raise unittest.SkipTest('Project requested skipping: ' + srcdir) except Exception: @@ -3171,6 +3172,50 @@ int main(int argc, char **argv) { ]: self.assertRegex(out, re.escape(expected)) + for wd in [ + self.src_root, + self.builddir, + os.getcwd(), + ]: + self.new_builddir() + out = self.init(tdir, workdir=wd) + expected = os.path.join(relpath(tdir, self.src_root), 'meson.build') + relwd = relpath(self.src_root, wd) + if relwd != '.': + expected = os.path.join(relwd, expected) + expected = '\n' + expected + ':' + self.assertIn(expected, out) + + def test_error_location_path(self): + '''Test locations in meson errors contain correct paths''' + # this list contains errors from all the different steps in the + # lexer/parser/interpreter we have tests for. + for (t, f) in [ + ('10 out of bounds', 'meson.build'), + ('18 wrong plusassign', 'meson.build'), + ('61 bad option argument', 'meson_options.txt'), + ('100 subdir parse error', os.path.join('subdir', 'meson.build')), + ('101 invalid option file', 'meson_options.txt'), + ]: + tdir = os.path.join(self.src_root, 'test cases', 'failing', t) + + for wd in [ + self.src_root, + self.builddir, + os.getcwd(), + ]: + try: + self.init(tdir, workdir=wd) + except subprocess.CalledProcessError as e: + expected = os.path.join('test cases', 'failing', t, f) + relwd = relpath(self.src_root, wd) + if relwd != '.': + expected = os.path.join(relwd, expected) + expected = '\n' + expected + ':' + self.assertIn(expected, e.output) + else: + self.fail('configure unexpectedly succeeded') + def test_permitted_method_kwargs(self): tdir = os.path.join(self.unit_test_dir, '25 non-permitted kwargs') out = self.init(tdir) diff --git a/test cases/failing/100 subdir parse error/meson.build b/test cases/failing/100 subdir parse error/meson.build new file mode 100644 index 0000000..ee5bb0c --- /dev/null +++ b/test cases/failing/100 subdir parse error/meson.build @@ -0,0 +1,2 @@ +project('subdir false plusassign', 'c') +subdir('subdir') diff --git a/test cases/failing/100 subdir parse error/subdir/meson.build b/test cases/failing/100 subdir parse error/subdir/meson.build new file mode 100644 index 0000000..3ac5ef9 --- /dev/null +++ b/test cases/failing/100 subdir parse error/subdir/meson.build @@ -0,0 +1 @@ +3 += 4 diff --git a/test cases/failing/101 invalid option file/meson.build b/test cases/failing/101 invalid option file/meson.build new file mode 100644 index 0000000..b0347c3 --- /dev/null +++ b/test cases/failing/101 invalid option file/meson.build @@ -0,0 +1 @@ +project('invalid option file') diff --git a/test cases/failing/101 invalid option file/meson_options.txt b/test cases/failing/101 invalid option file/meson_options.txt new file mode 100644 index 0000000..eef843b --- /dev/null +++ b/test cases/failing/101 invalid option file/meson_options.txt @@ -0,0 +1 @@ +' |