in src/python/pants/build_graph/build_file_parser.py [0:0]
def parse_build_file(self, build_file):
"""Capture Addressable instances from parsing `build_file`.
Prepare a context for parsing, read a BUILD file from the filesystem, and return the
Addressable instances generated by executing the code.
"""
def _format_context_msg(lineno, offset, error_type, message):
"""Show the line of the BUILD file that has the error along with a few line of context"""
build_contents = build_file.source().decode('utf-8')
context = "While parsing {build_file}:\n".format(build_file=build_file)
curr_lineno = 0
for line in build_contents.split('\n'):
line = line.encode('ascii', 'backslashreplace')
curr_lineno += 1
if curr_lineno == lineno:
highlight = '*'
else:
highlight = ' '
if curr_lineno >= lineno - 3:
context += "{highlight}{curr_lineno:4d}: {line}\n".format(
highlight=highlight, line=line, curr_lineno=curr_lineno)
if lineno == curr_lineno:
if offset:
context += (" {caret:>{width}} {error_type}: {message}\n\n"
.format(caret="^", width=int(offset), error_type=error_type,
message=message))
else:
context += (" {error_type}: {message}\n\n"
.format(error_type=error_type, message=message))
if curr_lineno > lineno + 3:
break
return context
logger.debug("Parsing BUILD file {build_file}."
.format(build_file=build_file))
try:
build_file_code = build_file.code()
except SyntaxError as e:
raise self.ParseError(_format_context_msg(e.lineno, e.offset, e.__class__.__name__, e))
except Exception as e:
raise self.ParseError("{error_type}: {message}\n while parsing BUILD file {build_file}"
.format(error_type=e.__class__.__name__,
message=e, build_file=build_file))
parse_state = self._build_configuration.initialize_parse_state(build_file)
try:
with warnings.catch_warnings(record=True) as warns:
six.exec_(build_file_code, parse_state.parse_globals)
for warn in warns:
logger.warning(_format_context_msg(lineno=warn.lineno,
offset=None,
error_type=warn.category.__name__,
message=warn.message))
except Exception as e:
raise self.ExecuteError("{message}\n while executing BUILD file {build_file}"
.format(message=e, build_file=build_file))
name_map = {}
for addressable in parse_state.objects:
name = addressable.addressed_name
logger.debug('Adding {addressable} to the BuildFileParser address map for {build_file} with {name}'
.format(addressable=addressable,
build_file=build_file,
name=name))
if name in name_map:
raise self.AddressableConflictException(
"File {conflicting_file} defines address '{target_name}' more than once."
.format(conflicting_file=build_file,
target_name=name))
name_map[name] = addressable
logger.debug("{build_file} produced the following Addressables:"
.format(build_file=build_file))
address_map = {}
for name, addressable in name_map.items():
address_map[BuildFileAddress(build_file=build_file, target_name=name)] = addressable
logger.debug(" * {name}: {addressable}"
.format(name=name,
addressable=addressable))
return address_map