| # Copyright 2021 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Runtime functions.""" |
| |
| _soong_config_namespaces_key = "$SOONG_CONFIG_NAMESPACES" |
| _dist_for_goals_key = "$dist_for_goals" |
| def _init_globals(input_variables_init): |
| """Initializes dictionaries of global variables. |
| |
| This function runs the given input_variables_init function, |
| passing it a globals dictionary and a handle as if it |
| were a regular product. It then returns 2 copies of |
| the globals dictionary, so that one can be kept around |
| to diff changes made to the other later. |
| """ |
| globals_base = {"PRODUCT_SOONG_NAMESPACES": []} |
| input_variables_init(globals_base, __h_new()) |
| |
| # Rerun input_variables_init to produce a copy |
| # of globals_base, because starlark doesn't support |
| # deep copying objects. |
| globals = {"PRODUCT_SOONG_NAMESPACES": []} |
| input_variables_init(globals, __h_new()) |
| |
| # Variables that should be defined. |
| mandatory_vars = [ |
| "PLATFORM_VERSION_CODENAME", |
| "PLATFORM_VERSION", |
| "PRODUCT_SOONG_NAMESPACES", |
| # TODO(asmundak): do we need TARGET_ARCH? AOSP does not reference it |
| "TARGET_BUILD_VARIANT", |
| "TARGET_PRODUCT", |
| ] |
| for bv in mandatory_vars: |
| if not bv in globals: |
| fail(bv, " is not defined") |
| |
| return (globals, globals_base) |
| |
| def __print_attr(attr, value): |
| # Allow using empty strings to clear variables, but not None values |
| if value == None: |
| return |
| if type(value) == "list": |
| if _options.rearrange: |
| value = __printvars_rearrange_list(value) |
| if _options.format == "pretty": |
| print(attr, "=", repr(value)) |
| elif _options.format == "make": |
| print(attr, ":=", " ".join(value)) |
| elif _options.format == "pretty": |
| print(attr, "=", repr(value)) |
| elif _options.format == "make": |
| # Trim all spacing to a single space |
| print(attr, ":=", _mkstrip(value)) |
| else: |
| fail("bad output format", _options.format) |
| |
| def _printvars(state): |
| """Prints configuration and global variables.""" |
| (globals, cfg, globals_base) = state |
| for attr, val in sorted(cfg.items()): |
| __print_attr(attr, val) |
| if _options.print_globals: |
| print() |
| _printglobals(globals, globals_base) |
| |
| def _printglobals(globals, globals_base): |
| for attr, val in sorted(globals.items()): |
| if attr == _soong_config_namespaces_key: |
| __print_attr("SOONG_CONFIG_NAMESPACES", val.keys()) |
| for nsname, nsvars in sorted(val.items()): |
| # Define SOONG_CONFIG_<ns> for Make, othewise |
| # it cannot be added to .KATI_READONLY list |
| if _options.format == "make": |
| print("SOONG_CONFIG_" + nsname, ":=", " ".join(nsvars.keys())) |
| for var, val in sorted(nsvars.items()): |
| if val: |
| __print_attr("SOONG_CONFIG_%s_%s" % (nsname, var), val) |
| else: |
| print("SOONG_CONFIG_%s_%s :=" % (nsname, var)) |
| elif attr == _dist_for_goals_key: |
| goals = [] |
| src_dst_list = [] |
| goal_dst_list = [] |
| for goal_name, goal_src_dst_list in sorted(val.items()): |
| goals.append(goal_name) |
| for sd in sorted(goal_src_dst_list): |
| src_dst_list.append(":".join(sd)) |
| goal_dst_list.append(":".join((goal_name, sd[1]))) |
| print("_all_dist_goal_output_pairs:=", " ".join(goal_dst_list)) |
| print("_all_dist_goals:=", " ".join(goals)) |
| print("_all_dist_src_dst_pairs:=", " ".join(src_dst_list)) |
| elif attr not in globals_base or globals_base[attr] != val: |
| __print_attr(attr, val) |
| |
| def __printvars_rearrange_list(value_list): |
| """Rearrange value list: return only distinct elements, maybe sorted.""" |
| seen = {item: 0 for item in value_list} |
| return sorted(seen.keys()) if _options.rearrange == "sort" else seen.keys() |
| |
| def _product_configuration(top_pcm_name, top_pcm, input_variables_init): |
| """Creates configuration.""" |
| |
| # Product configuration is created by traversing product's inheritance |
| # tree. It is traversed twice. |
| # First, beginning with top-level module we execute a module and find |
| # its ancestors, repeating this recursively. At the end of this phase |
| # we get the full inheritance tree. |
| # Second, we traverse the tree in the postfix order (i.e., visiting a |
| # node after its ancestors) to calculate the product configuration. |
| # |
| # PCM means "Product Configuration Module", i.e., a Starlark file |
| # whose body consists of a single init function. |
| |
| globals, globals_base = _init_globals(input_variables_init) |
| |
| config_postfix = [] # Configs in postfix order |
| |
| # Each PCM is represented by a quadruple of function, config, children names |
| # and readyness (that is, the configurations from inherited PCMs have been |
| # substituted). |
| configs = {top_pcm_name: (top_pcm, None, [], False)} # All known PCMs |
| |
| stash = [] # Configs to push once their descendants are done |
| |
| # Stack containing PCMs to be processed. An item in the stack |
| # is a pair of PCMs name and its height in the product inheritance tree. |
| pcm_stack = [(top_pcm_name, 0)] |
| pcm_count = 0 |
| |
| # Run it until pcm_stack is exhausted, but no more than N times |
| for n in range(1000): |
| if not pcm_stack: |
| break |
| (name, height) = pcm_stack.pop() |
| pcm, cfg, c, _ = configs[name] |
| |
| # cfg is set only after PCM has been called, leverage this |
| # to prevent calling the same PCM twice |
| if cfg != None: |
| continue |
| |
| # Push ancestors until we reach this node's height |
| config_postfix.extend([stash.pop() for i in range(len(stash) - height)]) |
| |
| # Run this one, obtaining its configuration and child PCMs. |
| if _options.trace_modules: |
| print("%d:" % n) |
| |
| # Run PCM. |
| handle = __h_new() |
| pcm(globals, handle) |
| |
| # Now we know everything about this PCM, record it in 'configs'. |
| children = __h_inherited_modules(handle) |
| if _options.trace_modules: |
| print(" ", " ".join(children.keys())) |
| configs[name] = (pcm, __h_cfg(handle), children.keys(), False) |
| pcm_count = pcm_count + 1 |
| |
| if len(children) == 0: |
| # Leaf PCM goes straight to the config_postfix |
| config_postfix.append(name) |
| continue |
| |
| # Stash this PCM, process children in the sorted order |
| stash.append(name) |
| for child_name in sorted(children, reverse = True): |
| if child_name not in configs: |
| configs[child_name] = (children[child_name], None, [], False) |
| pcm_stack.append((child_name, len(stash))) |
| if pcm_stack: |
| fail("Inheritance processing took too many iterations") |
| |
| # Flush the stash |
| config_postfix.extend([stash.pop() for i in range(len(stash))]) |
| if len(config_postfix) != pcm_count: |
| fail("Ran %d modules but postfix tree has only %d entries" % (pcm_count, len(config_postfix))) |
| |
| if _options.trace_modules: |
| print("\n---Postfix---") |
| for x in config_postfix: |
| print(" ", x) |
| |
| # Traverse the tree from the bottom, evaluating inherited values |
| for pcm_name in config_postfix: |
| pcm, cfg, children_names, ready = configs[pcm_name] |
| |
| # Should run |
| if cfg == None: |
| fail("%s: has not been run" % pcm_name) |
| |
| # Ready once |
| if ready: |
| continue |
| |
| # Children should be ready |
| for child_name in children_names: |
| if not configs[child_name][3]: |
| fail("%s: child is not ready" % child_name) |
| |
| _substitute_inherited(configs, pcm_name, cfg) |
| _percolate_inherited(configs, pcm_name, cfg, children_names) |
| configs[pcm_name] = pcm, cfg, children_names, True |
| |
| return (globals, configs[top_pcm_name][1], globals_base) |
| |
| |
| def _dictionary_difference(a, b): |
| result = {} |
| for attr, val in a.items(): |
| if attr not in b or b[attr] != val: |
| result[attr] = val |
| return result |
| |
| def _board_configuration(board_config_init, input_variables_init): |
| globals_base = {} |
| h_base = __h_new() |
| globals = {} |
| h = __h_new() |
| |
| input_variables_init(globals_base, h_base) |
| input_variables_init(globals, h) |
| board_config_init(globals, h) |
| return (globals, _dictionary_difference(h[0], h_base[0]), globals_base) |
| |
| |
| def _substitute_inherited(configs, pcm_name, cfg): |
| """Substitutes inherited values in all the attributes. |
| |
| When a value of an attribute is a list, some of its items may be |
| references to a value of a same attribute in an inherited product, |
| e.g., for a given module PRODUCT_PACKAGES can be |
| ["foo", (submodule), "bar"] |
| and for 'submodule' PRODUCT_PACKAGES may be ["baz"] |
| (we use a tuple to distinguish submodule references). |
| After the substitution the value of PRODUCT_PACKAGES for the module |
| will become ["foo", "baz", "bar"] |
| """ |
| for attr, val in cfg.items(): |
| # TODO(asmundak): should we handle single vars? |
| if type(val) != "list": |
| continue |
| |
| if attr not in _options.trace_variables: |
| cfg[attr] = _value_expand(configs, attr, val) |
| else: |
| old_val = val |
| new_val = _value_expand(configs, attr, val) |
| if new_val != old_val: |
| print("%s(i): %s=%s (was %s)" % (pcm_name, attr, new_val, old_val)) |
| cfg[attr] = new_val |
| |
| def _value_expand(configs, attr, values_list): |
| """Expands references to inherited values in a given list.""" |
| result = [] |
| expanded = {} |
| for item in values_list: |
| # Inherited values are 1-tuples |
| if type(item) != "tuple": |
| result.append(item) |
| continue |
| child_name = item[0] |
| if child_name in expanded: |
| continue |
| expanded[child_name] = True |
| child = configs[child_name] |
| if not child[3]: |
| fail("%s should be ready" % child_name) |
| __move_items(result, child[1], attr) |
| |
| return result |
| |
| def _percolate_inherited(configs, cfg_name, cfg, children_names): |
| """Percolates the settings that are present only in children.""" |
| percolated_attrs = {} |
| for child_name in children_names: |
| child_cfg = configs[child_name][1] |
| for attr, value in child_cfg.items(): |
| if type(value) != "list": |
| if attr in percolated_attrs or not attr in cfg: |
| cfg[attr] = value |
| percolated_attrs[attr] = True |
| continue |
| if attr in percolated_attrs: |
| # We already are percolating this one, just add this list |
| __move_items(cfg[attr], child_cfg, attr) |
| elif not attr in cfg: |
| percolated_attrs[attr] = True |
| cfg[attr] = [] |
| __move_items(cfg[attr], child_cfg, attr) |
| |
| for attr in _options.trace_variables: |
| if attr in percolated_attrs: |
| print("%s: %s^=%s" % (cfg_name, attr, cfg[attr])) |
| |
| def __move_items(to_list, from_cfg, attr): |
| value = from_cfg.get(attr, []) |
| if value: |
| to_list.extend(value) |
| from_cfg[attr] = [] |
| |
| def _indirect(pcm_name): |
| """Returns configuration item for the inherited module.""" |
| return (pcm_name,) |
| |
| def _soong_config_namespace(g, nsname): |
| """Adds given namespace if it does not exist.""" |
| |
| old = g.get(_soong_config_namespaces_key, {}) |
| if old.get(nsname): |
| return |
| |
| # A value cannot be updated, so we need to create a new dictionary |
| g[_soong_config_namespaces_key] = dict([(k,v) for k,v in old.items()] + [(nsname, {})]) |
| |
| def _soong_config_set(g, nsname, var, value): |
| """Assigns the value to the variable in the namespace.""" |
| _soong_config_namespace(g, nsname) |
| g[_soong_config_namespaces_key][nsname][var]=value |
| |
| def _soong_config_append(g, nsname, var, value): |
| """Appends to the value of the variable in the namespace.""" |
| _soong_config_namespace(g, nsname) |
| ns = g[_soong_config_namespaces_key][nsname] |
| oldv = ns.get(var) |
| if oldv == None: |
| ns[var] = value |
| else: |
| ns[var] += " " + value |
| |
| |
| def _soong_config_get(g, nsname, var): |
| """Gets to the value of the variable in the namespace.""" |
| return g.get(_soong_config_namespaces_key, {}).get(nsname, {}).get(var, None) |
| |
| |
| def _abspath(path): |
| """Provided for compatibility, to be removed later.""" |
| return path |
| |
| |
| def _addprefix(prefix, string_or_list): |
| """Adds prefix and returns a list. |
| |
| If string_or_list is a list, prepends prefix to each element. |
| Otherwise, string_or_list is considered to be a string which |
| is split into words and then prefix is prepended to each one. |
| |
| Args: |
| prefix |
| string_or_list |
| |
| """ |
| return [prefix + x for x in __words(string_or_list)] |
| |
| def _addsuffix(suffix, string_or_list): |
| """Adds suffix and returns a list. |
| |
| If string_or_list is a list, appends suffix to each element. |
| Otherwise, string_or_list is considered to be a string which |
| is split into words and then suffix is appended to each one. |
| |
| Args: |
| suffix |
| string_or_list |
| """ |
| return [x + suffix for x in __words(string_or_list)] |
| |
| def __words(string_or_list): |
| if type(string_or_list) == "list": |
| return string_or_list |
| return _mkstrip(string_or_list).split() |
| |
| # Handle manipulation functions. |
| # A handle passed to a PCM consists of: |
| # product attributes dict ("cfg") |
| # inherited modules dict (maps module name to PCM) |
| # default value list (initially empty, modified by inheriting) |
| def __h_new(): |
| """Constructs a handle which is passed to PCM.""" |
| return (dict(), dict(), list()) |
| |
| def __h_inherited_modules(handle): |
| """Returns PCM's inherited modules dict.""" |
| return handle[1] |
| |
| def __h_cfg(handle): |
| """Returns PCM's product configuration attributes dict. |
| |
| This function is also exported as rblf.cfg, and every PCM |
| calls it at the beginning. |
| """ |
| return handle[0] |
| |
| def _setdefault(handle, attr): |
| """If attribute has not been set, assigns default value to it. |
| |
| This function is exported as rblf.setdefault(). |
| Only list attributes are initialized this way. The default |
| value is kept in the PCM's handle. Calling inherit() updates it. |
| """ |
| cfg = handle[0] |
| if cfg.get(attr) == None: |
| cfg[attr] = list(handle[2]) |
| return cfg[attr] |
| |
| def _inherit(handle, pcm_name, pcm): |
| """Records inheritance. |
| |
| This function is exported as rblf.inherit, PCM calls it when |
| a module is inherited. |
| """ |
| cfg, inherited, default_lv = handle |
| inherited[pcm_name] = pcm |
| default_lv.append(_indirect(pcm_name)) |
| |
| # Add inherited module reference to all configuration values |
| for attr, val in cfg.items(): |
| if type(val) == "list": |
| val.append(_indirect(pcm_name)) |
| |
| def __base(path): |
| """Returns basename.""" |
| return path.rsplit("/",1)[-1] |
| |
| def _board_platform_in(g, string_or_list): |
| """Returns true if board is in the list.""" |
| board = g.get("TARGET_BOARD_PLATFORM","") |
| if not board: |
| return False |
| return board in __words(string_or_list) |
| |
| |
| def _board_platform_is(g, s): |
| """True if board is the same as argument.""" |
| return g.get("TARGET_BOARD_PLATFORM","") == s |
| |
| |
| def _copy_files(l, outdir): |
| """Generate <item>:<outdir>/item for each item.""" |
| return ["%s:%s/%s" % (path, outdir, __base(path)) for path in __words(l)] |
| |
| def _copy_if_exists(path_pair): |
| """If from file exists, returns [from:to] pair.""" |
| value = path_pair.split(":", 2) |
| |
| # Check that l[0] exists |
| return [":".join(value)] if rblf_file_exists(value[0]) else [] |
| |
| def _enforce_product_packages_exist(pkg_string_or_list): |
| """Makes including non-existent modules in PRODUCT_PACKAGES an error.""" |
| |
| #TODO(asmundak) |
| pass |
| |
| def _file_wildcard_exists(file_pattern): |
| """Return True if there are files matching given bash pattern.""" |
| return len(rblf_wildcard(file_pattern)) > 0 |
| |
| def _find_and_copy(pattern, from_dir, to_dir): |
| """Return a copy list for the files matching the pattern.""" |
| return sorted(["%s/%s:%s/%s" % ( |
| from_dir, f, to_dir, f) for f in rblf_find_files(from_dir, pattern, only_files=1)]) |
| |
| def _findstring(needle, haystack): |
| """Equivalent to GNU make's $(findstring).""" |
| if haystack.find(needle) < 0: |
| return "" |
| return needle |
| |
| def _filter_out(pattern, text): |
| """Return all the words from `text' that do not match any word in `pattern'. |
| |
| Args: |
| pattern: string or list of words. '%' stands for wildcard (in regex terms, '.*') |
| text: string or list of words |
| Return: |
| list of words |
| """ |
| rex = __mk2regex(__words(pattern)) |
| res = [] |
| for w in __words(text): |
| if not _regex_match(rex, w): |
| res.append(w) |
| return res |
| |
| def _filter(pattern, text): |
| """Return all the words in `text` that match `pattern`. |
| |
| Args: |
| pattern: strings of words or a list. A word can contain '%', |
| which stands for any sequence of characters. |
| text: string or list of words. |
| """ |
| rex = __mk2regex(__words(pattern)) |
| res = [] |
| for w in __words(text): |
| if _regex_match(rex, w): |
| res.append(w) |
| return res |
| |
| def _notdir(paths): |
| """Equivalent to the GNU make function $(notdir). |
| |
| Returns the name of the file at the end of each path in paths. |
| """ |
| return " ".join([__base(w) for w in __words(paths)]) |
| |
| def __mk2regex(words): |
| """Returns regular expression equivalent to Make pattern.""" |
| |
| # TODO(asmundak): this will mishandle '\%' |
| return "^(" + "|".join([w.replace("%", ".*", 1) for w in words if w]) + ")$" |
| |
| def _regex_match(regex, w): |
| return rblf_regex(regex, w) |
| |
| def _require_artifacts_in_path(paths, allowed_paths): |
| """TODO.""" |
| pass |
| |
| def _require_artifacts_in_path_relaxed(paths, allowed_paths): |
| """TODO.""" |
| pass |
| |
| def _expand_wildcard(pattern): |
| """Expands shell wildcard pattern.""" |
| result = [] |
| for word in __words(pattern): |
| result.extend(rblf_wildcard(word)) |
| return result |
| |
| def _mkdist_for_goals(g, goal, src_dst_list): |
| """Implements dist-for-goals macro.""" |
| goals_map = g.get(_dist_for_goals_key, {}) |
| pairs = goals_map.get(goal) |
| if pairs == None: |
| pairs = [] |
| g[_dist_for_goals_key] = dict([(k,v) for k,v in goals_map.items()] + [(goal, pairs)]) |
| for src_dst in __words(src_dst_list): |
| pair=src_dst.split(":") |
| if len(pair) > 2: |
| fail(src_dst + " should be a :-separated pair") |
| pairs.append((pair[0],pair[1] if len(pair) == 2 and pair[1] else __base(pair[0]))) |
| g[_dist_for_goals_key][goal] = pairs |
| |
| |
| def _mkerror(file, message = ""): |
| """Prints error and stops.""" |
| fail("%s: %s. Stop" % (file, message)) |
| |
| def _mkwarning(file, message = ""): |
| """Prints warning.""" |
| rblf_log(file, "warning", message, sep = ':') |
| |
| def _mk2rbc_error(loc, message): |
| """Prints a message about conversion error and stops. |
| |
| If RBC_MK2RBC_CONTINUE environment variable is set, |
| the execution will continue after the message is printed. |
| """ |
| if _options.mk2rbc_continue: |
| rblf_log(loc, message, sep = ':') |
| else: |
| _mkerror(loc, message) |
| |
| |
| def _mkinfo(file, message = ""): |
| """Prints info.""" |
| rblf_log(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): |
| return word |
| if not word.endswith(after): |
| return word |
| if len(parsed_subst) < 2: |
| return parsed_subst[0] |
| return parsed_subst[0] + word[len(before):len(word) - len(after)] + parsed_subst[1] |
| |
| |
| def _mkpatsubst(pattern, replacement, s): |
| """Emulates Make's patsubst. |
| |
| 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). |
| """ |
| 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 = __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) |
| |
| |
| def _mkstrip(s): |
| """Emulates Make's strip. |
| |
| That is, removes string's leading and trailing whitespace characters and |
| replaces any sequence of whitespace characters with with a single space. |
| """ |
| if type(s) != "string": |
| return s |
| result = "" |
| was_space = False |
| for ch in s.strip().elems(): |
| is_space = ch.isspace() |
| if not is_space: |
| if was_space: |
| result += " " |
| result += ch |
| was_space = is_space |
| return result |
| |
| def _mksubst(old, new, s): |
| """Emulates Make's subst. |
| |
| Replaces each occurence of 'old' with 'new'. |
| If 's' is a list, applies substitution to each item. |
| """ |
| if type(s) == "list": |
| return [e.replace(old, new) for e in s] |
| 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( |
| format = "pretty", |
| print_globals = False, |
| rearrange = "", |
| trace_modules = False, |
| trace_variables = [], |
| mk2rbc_continue = False, |
| ) |
| for x in getattr(rblf_cli, "RBC_OUT", "").split(","): |
| if x == "sort" or x == "unique": |
| if settings["rearrange"]: |
| fail("RBC_OUT: either sort or unique is allowed (and sort implies unique)") |
| settings["rearrange"] = x |
| elif x == "pretty" or x == "make": |
| settings["format"] = x |
| elif x == "global": |
| settings["print_globals"] = True |
| elif x != "": |
| fail("RBC_OUT: got %s, should be one of: [pretty|make] [sort|unique]" % x) |
| for x in getattr(rblf_cli, "RBC_DEBUG", "").split(","): |
| if x == "!trace": |
| settings["trace_modules"] = True |
| elif x != "": |
| settings["trace_variables"].append(x) |
| if getattr(rblf_cli, "RBC_MK2RBC_CONTINUE", ""): |
| settings["mk2rbc_continue"] = True |
| return struct(**settings) |
| |
| # Settings used during debugging. |
| _options = __get_options() |
| rblf = struct( |
| soong_config_namespace = _soong_config_namespace, |
| soong_config_append = _soong_config_append, |
| soong_config_set = _soong_config_set, |
| soong_config_get = _soong_config_get, |
| abspath = _abspath, |
| addprefix = _addprefix, |
| addsuffix = _addsuffix, |
| board_platform_in = _board_platform_in, |
| board_platform_is = _board_platform_is, |
| copy_files = _copy_files, |
| copy_if_exists = _copy_if_exists, |
| cfg = __h_cfg, |
| enforce_product_packages_exist = _enforce_product_packages_exist, |
| expand_wildcard = _expand_wildcard, |
| file_exists = rblf_file_exists, |
| file_wildcard_exists = _file_wildcard_exists, |
| filter = _filter, |
| filter_out = _filter_out, |
| find_and_copy = _find_and_copy, |
| findstring = _findstring, |
| inherit = _inherit, |
| indirect = _indirect, |
| mk2rbc_error = _mk2rbc_error, |
| mkdist_for_goals = _mkdist_for_goals, |
| mkinfo = _mkinfo, |
| mkerror = _mkerror, |
| mkpatsubst = _mkpatsubst, |
| mkwarning = _mkwarning, |
| mkstrip = _mkstrip, |
| mksubst = _mksubst, |
| notdir = _notdir, |
| printvars = _printvars, |
| printglobals = _printglobals, |
| product_configuration = _product_configuration, |
| board_configuration = _board_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, |
| shell = rblf_shell, |
| warning = _mkwarning, |
| words = __words, |
| ) |