1# Copyright 2019 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Utilities for maprule.""" 16 17def resolve_locations(ctx, strategy, d): 18 """Resolve $(location) references in the values of a dictionary. 19 20 Args: 21 ctx: the 'ctx' argument of the rule implementation function 22 strategy: a struct with an 'as_path(string) -> string' function 23 d: {string: string} dictionary; values may contain $(location) references 24 for labels declared in the rule's 'srcs' and 'tools' attributes 25 26 Returns: 27 {string: string} dict, same as 'd' except "$(location)" references are 28 resolved. 29 """ 30 location_expressions = [] 31 parts = {} 32 was_anything_to_resolve = False 33 for k, v in d.items(): 34 # Look for "$(location ...)" or "$(locations ...)", resolve if found. 35 # _validate_attributes already ensured that there's at most one $(location/s ...) in "v". 36 if "$(location" in v: 37 tokens = v.split("$(location") 38 was_anything_to_resolve = True 39 closing_paren = tokens[1].find(")") 40 location_expressions.append("$(location" + tokens[1][:closing_paren + 1]) 41 parts[k] = (tokens[0], tokens[1][closing_paren + 1:]) 42 else: 43 location_expressions.append("") 44 45 resolved = {} 46 if was_anything_to_resolve: 47 # Resolve all $(location) expressions in one go. Should be faster than resolving them 48 # one-by-one. 49 all_location_expressions = "<split_here>".join(location_expressions) 50 all_resolved_locations = ctx.expand_location(all_location_expressions) 51 resolved_locations = strategy.as_path(all_resolved_locations).split("<split_here>") 52 53 i = 0 54 55 # Starlark dictionaries have a deterministic order of iteration, so the element order in 56 # "resolved_locations" matches the order in "location_expressions", i.e. the previous 57 # iteration order of "d". 58 for k, v in d.items(): 59 if location_expressions[i]: 60 head, tail = parts[k] 61 resolved[k] = head + resolved_locations[i] + tail 62 else: 63 resolved[k] = v 64 i += 1 65 else: 66 resolved = d 67 68 return resolved 69 70def fail_if_errors(errors): 71 """Reports errors and fails the rule. 72 73 Args: 74 errors: list of strings; the errors to report. At most 10 are reported. 75 """ 76 if errors: 77 # Don't overwhelm the user; report up to ten errors. 78 fail("\n".join(errors[:10])) 79 80def _as_windows_path(s): 81 """Returns the input path as a Windows path (replaces all of "/" with "\").""" 82 return s.replace("/", "\\") 83 84def _unchanged_path(s): 85 """Returns the input string (path) unchanged.""" 86 return s 87 88def _create_cmd_action( 89 ctx, 90 outputs, 91 command, 92 inputs = None, 93 env = None, 94 progress_message = None, 95 mnemonic = None, 96 manifests_from_tools = None): 97 """Create one action using cmd.exe.""" 98 ctx.actions.run( 99 inputs = inputs or [], 100 outputs = outputs, 101 executable = "cmd.exe", 102 env = env, 103 arguments = ["/C", command], 104 progress_message = progress_message or "Running cmd.exe command", 105 mnemonic = mnemonic or "CmdExeCommand", 106 input_manifests = manifests_from_tools, 107 ) 108 109def _create_bash_action( 110 ctx, 111 outputs, 112 command, 113 inputs = None, 114 env = None, 115 progress_message = None, 116 mnemonic = None, 117 manifests_from_tools = None): 118 """Create one action using Bash.""" 119 ctx.actions.run_shell( 120 inputs = inputs or [], 121 outputs = outputs, 122 env = env, 123 command = command, 124 progress_message = progress_message or "Running Bash command", 125 mnemonic = mnemonic or "BashCommand", 126 input_manifests = manifests_from_tools, 127 ) 128 129# Action creation utilities for cmd.exe actions. 130CMD_STRATEGY = struct( 131 as_path = _as_windows_path, 132 create_action = _create_cmd_action, 133) 134 135# Action creation utilities for Bash actions. 136BASH_STRATEGY = struct( 137 as_path = _unchanged_path, 138 create_action = _create_bash_action, 139) 140