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