163 lines
5.0 KiB
Python
163 lines
5.0 KiB
Python
|
# Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights
|
||
|
# reserved. Use of this source code is governed by a BSD-style license that
|
||
|
# can be found in the LICENSE file.
|
||
|
|
||
|
QUIET = False
|
||
|
|
||
|
|
||
|
def bazel_set_quiet(quiet):
|
||
|
global QUIET
|
||
|
QUIET = quiet
|
||
|
|
||
|
|
||
|
LAST_ERROR = None
|
||
|
|
||
|
|
||
|
def bazel_last_error():
|
||
|
return LAST_ERROR
|
||
|
|
||
|
|
||
|
def _set_last_error(error):
|
||
|
global LAST_ERROR
|
||
|
LAST_ERROR = error
|
||
|
|
||
|
|
||
|
def _print(label, data, pos, msg):
|
||
|
data_to_pos = data[0:pos]
|
||
|
line = data_to_pos.count('\n')
|
||
|
pos_in_line = (pos - data_to_pos.rfind('\n') - 1) if line > 0 else pos
|
||
|
|
||
|
_set_last_error('ERROR: %s: %s at line %d:%d' % (label, msg, line + 1,
|
||
|
pos_in_line + 1))
|
||
|
if not QUIET:
|
||
|
print(LAST_ERROR)
|
||
|
|
||
|
|
||
|
def bazel_substitute(data,
|
||
|
variables,
|
||
|
var_delim_start='${',
|
||
|
var_delim_end='}',
|
||
|
path_list_delim=',\n ',
|
||
|
path_relative_to=None,
|
||
|
path_abs_prefix='//',
|
||
|
label='data'):
|
||
|
_set_last_error(None)
|
||
|
|
||
|
if not path_relative_to is None and len(path_relative_to) == 0:
|
||
|
path_relative_to = None
|
||
|
if not path_relative_to is None and path_relative_to[-1] != '/':
|
||
|
path_relative_to += '/'
|
||
|
|
||
|
result = ''
|
||
|
|
||
|
epos = 0
|
||
|
spos = data.find(var_delim_start, epos)
|
||
|
while spos >= 0:
|
||
|
result += data[epos:spos]
|
||
|
epos = data.find(var_delim_end, spos + len(var_delim_start))
|
||
|
if epos > spos:
|
||
|
sub = ''
|
||
|
var = data[spos + len(var_delim_start):epos]
|
||
|
if var in variables:
|
||
|
val = variables[var]
|
||
|
if isinstance(val, list):
|
||
|
# Assumed to be a list of file paths.
|
||
|
paths = []
|
||
|
for path in val:
|
||
|
if not path_relative_to is None and path.startswith(
|
||
|
path_relative_to):
|
||
|
# Use only the remainder of the path.
|
||
|
path = path[len(path_relative_to):]
|
||
|
else:
|
||
|
# Use a fully qualified path.
|
||
|
path = path_abs_prefix + path
|
||
|
paths.append('"%s"' % path)
|
||
|
sub = path_list_delim.join(paths)
|
||
|
else:
|
||
|
# Direct replacement.
|
||
|
sub = str(val)
|
||
|
else:
|
||
|
_print(label, data, spos,
|
||
|
'No value for "%s%s%s"' % (var_delim_start, var, var_delim_end))
|
||
|
if len(sub) > 0:
|
||
|
result += sub
|
||
|
epos += len(var_delim_end)
|
||
|
else:
|
||
|
_print(label, data, spos,
|
||
|
'Missing close bracket for "%s..."' % (data[spos:spos + 5]))
|
||
|
# Can't parse any further.
|
||
|
break
|
||
|
spos = data.find(var_delim_start, epos)
|
||
|
|
||
|
if epos >= 0:
|
||
|
result += data[epos:]
|
||
|
|
||
|
return result
|
||
|
|
||
|
|
||
|
# Test the module.
|
||
|
if __name__ == "__main__":
|
||
|
# Don't print error messages.
|
||
|
bazel_set_quiet(True)
|
||
|
|
||
|
# No substitution
|
||
|
assert (bazel_substitute('foobar', {}) == 'foobar')
|
||
|
assert (bazel_last_error() == None)
|
||
|
|
||
|
# No matching variable
|
||
|
assert (bazel_substitute('${a}foobar', {}) == 'foobar')
|
||
|
assert (bazel_last_error() == 'ERROR: data: No value for "${a}" at line 1:1')
|
||
|
assert (bazel_substitute('\nfoo${a}bar', {}) == '\nfoobar')
|
||
|
assert (bazel_last_error() == 'ERROR: data: No value for "${a}" at line 2:4')
|
||
|
assert (bazel_substitute('\n\nfoobar${a}', {}) == '\n\nfoobar')
|
||
|
assert (bazel_last_error() == 'ERROR: data: No value for "${a}" at line 3:7')
|
||
|
|
||
|
# Missing end bracket.
|
||
|
assert (bazel_substitute('${afoobar', {}) == '')
|
||
|
assert (bazel_last_error() ==
|
||
|
'ERROR: data: Missing close bracket for "${afo..." at line 1:1')
|
||
|
assert (bazel_substitute('\nfoo${abar', {}) == '\nfoo')
|
||
|
assert (bazel_last_error() ==
|
||
|
'ERROR: data: Missing close bracket for "${aba..." at line 2:4')
|
||
|
assert (bazel_substitute('\n\nfoobar${a', {}) == '\n\nfoobar')
|
||
|
assert (bazel_last_error() ==
|
||
|
'ERROR: data: Missing close bracket for "${a..." at line 3:7')
|
||
|
|
||
|
# Variable substitution
|
||
|
assert (bazel_substitute('foo${choo}bar', {'choo': 'blah'}) == 'fooblahbar')
|
||
|
assert (bazel_last_error() == None)
|
||
|
assert (bazel_substitute('${ah}${choo}bar${ba}',
|
||
|
{'ah': 'foo',
|
||
|
'choo': 5,
|
||
|
'ba': ''}) == 'foo5bar')
|
||
|
assert (bazel_last_error() == None)
|
||
|
|
||
|
# Custom variable delimiters.
|
||
|
assert (bazel_substitute(
|
||
|
'$$ah$$$$choo$$bar$$ba$$', {'ah': 'foo',
|
||
|
'choo': 5,
|
||
|
'ba': ''},
|
||
|
var_delim_start='$$',
|
||
|
var_delim_end='$$') == 'foo5bar')
|
||
|
assert (bazel_last_error() == None)
|
||
|
|
||
|
paths = [
|
||
|
'path/to/a.ext',
|
||
|
'path/to/b.ext',
|
||
|
'another/path/c.ext',
|
||
|
]
|
||
|
|
||
|
# All absolute paths.
|
||
|
assert (bazel_substitute('[${paths}]', {'paths': paths}, path_list_delim=',')
|
||
|
== '["//path/to/a.ext","//path/to/b.ext","//another/path/c.ext"]')
|
||
|
assert (bazel_last_error() == None)
|
||
|
|
||
|
# Some relative paths.
|
||
|
assert (bazel_substitute(
|
||
|
'[${paths}]', {'paths': paths},
|
||
|
path_list_delim=',',
|
||
|
path_relative_to='path/to') == '["a.ext","b.ext","//another/path/c.ext"]')
|
||
|
assert (bazel_last_error() == None)
|
||
|
|
||
|
print('Tests passed!')
|