Support product-copy-files-by-pattern macro
Bug: 193566316
Test: rbcrun build/make/tests/run.rbc
Change-Id: Idf462d7f58e8d4a6e8b3a1506306f9eb67130dc8
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 3714448..f7ce7aa 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -463,6 +463,28 @@
print(message)
+def __mkparse_pattern(pattern):
+ """Parses Make's patsubst pattern."""
+ in_escape = False
+ res = []
+ acc = ""
+ for c in pattern.elems():
+ if in_escape:
+ in_escape = False
+ acc += c
+ elif c == '\\':
+ in_escape = True
+ elif c == '%' and not res:
+ res.append(acc)
+ acc = ''
+ else:
+ acc += c
+ if in_escape:
+ acc += '\\'
+ res.append(acc)
+ return res
+
+
def __mkpatsubst_word(parsed_pattern,parsed_subst, word):
(before, after) = parsed_pattern
if not word.startswith(before):
@@ -480,16 +502,14 @@
Tokenizes `s` (unless it is already a list), and then performs a simple
wildcard substitution (in other words, `foo%bar` pattern is equivalent to
the regular expression `^foo(.*)bar$, and the first `%` in replacement is
- $1 in regex terms). Escaping % is not supported
+ $1 in regex terms).
"""
- if pattern.find("\\") >= 0:
- fail("'\\' in pattern is not allowed")
- parsed_pattern = pattern.split("%", 1)
+ parsed_pattern = __mkparse_pattern(pattern)
words = s if type(s) == "list" else _mkstrip(s).split(" ")
if len(parsed_pattern) == 1:
out_words = [ replacement if x == pattern else x for x in words]
else:
- parsed_replacement = replacement.split("%", 1)
+ parsed_replacement = __mkparse_pattern(replacement)
out_words = [__mkpatsubst_word(parsed_pattern, parsed_replacement, x) for x in words]
return out_words if type(s) == "list" else " ".join(out_words)
@@ -522,6 +542,22 @@
return s.replace(old, new)
+def _product_copy_files_by_pattern(src, dest, s):
+ """Creates a copy list.
+
+ For each item in a given list, create <from>:<to> pair, where <from> and
+ <to> are the results of applying Make-style patsubst of <src> and <dest>
+ respectively. E.g. the result of calling this function with
+ ("foo/%", "bar/%", ["a", "b"]) will be
+ ["foo/a:bar/a", "foo/b:bar/b"].
+ """
+ parsed_src = __mkparse_pattern(src)
+ parsed_dest = __mkparse_pattern(dest)
+ parsed_percent = ["", ""]
+ words = s if type(s) == "list" else _mkstrip(s).split(" ")
+ return [ __mkpatsubst_word(parsed_percent, parsed_src, x) + ":" + __mkpatsubst_word(parsed_percent, parsed_dest, x) for x in words]
+
+
def __get_options():
"""Returns struct containing runtime global settings."""
settings = dict(
@@ -577,6 +613,7 @@
mksubst = _mksubst,
printvars = _printvars,
product_configuration = _product_configuration,
+ product_copy_files_by_pattern = _product_copy_files_by_pattern,
require_artifacts_in_path = _require_artifacts_in_path,
require_artifacts_in_path_relaxed = _require_artifacts_in_path_relaxed,
setdefault = _setdefault,
diff --git a/tests/run.rbc b/tests/run.rbc
index 15f6212..35ae19d 100644
--- a/tests/run.rbc
+++ b/tests/run.rbc
@@ -43,6 +43,9 @@
assert_eq("azx b", rblf.mkpatsubst("az", "AZ", "azx b"))
assert_eq(["azx", "b"], rblf.mkpatsubst("az", "AZ", ["azx", "b"]))
assert_eq("ABC", rblf.mkpatsubst("abc", "ABC", "abc"))
+assert_eq(["%/foo"], rblf.mkpatsubst("%", "\\%/%", ["foo"]))
+assert_eq(["foo/%"], rblf.mkpatsubst("%", "%/%", ["foo"]))
+assert_eq(["from/a:to/a", "from/b:to/b"], rblf.product_copy_files_by_pattern("from/%", "to/%", "a b"))
globals, config = rblf.product_configuration("test/device", init)
assert_eq(