1*c8dee2aaSAndroid Build Coastguard Worker"""This module defines the remove_indentation macro.""" 2*c8dee2aaSAndroid Build Coastguard Worker 3*c8dee2aaSAndroid Build Coastguard Workerdef remove_indentation(string): 4*c8dee2aaSAndroid Build Coastguard Worker """Removes indentation from a multiline string. 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Worker This utility function allows us to write multiline templates in a context that requires 7*c8dee2aaSAndroid Build Coastguard Worker indentation, for example inside a macro. It discards the first and last lines if they only 8*c8dee2aaSAndroid Build Coastguard Worker contain spaces or tabs. Then, it computes an indentation prefix based on the first remaining 9*c8dee2aaSAndroid Build Coastguard Worker line and removes that prefix from all lines. 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker Example: 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker ``` 14*c8dee2aaSAndroid Build Coastguard Worker def greeter_script(): 15*c8dee2aaSAndroid Build Coastguard Worker return remove_indentation(''' 16*c8dee2aaSAndroid Build Coastguard Worker #!/bin/bash 17*c8dee2aaSAndroid Build Coastguard Worker echo "Hello, {name}!" 18*c8dee2aaSAndroid Build Coastguard Worker ''').format(name = "world") 19*c8dee2aaSAndroid Build Coastguard Worker ``` 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker This is equivalent to: 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker ``` 24*c8dee2aaSAndroid Build Coastguard Worker TEMPLATE = '''#!/bin/bash 25*c8dee2aaSAndroid Build Coastguard Worker echo "Hello, {name}!" 26*c8dee2aaSAndroid Build Coastguard Worker ''' 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker def greeter_script(): 29*c8dee2aaSAndroid Build Coastguard Worker return TEMPLATE.format(name = "world") 30*c8dee2aaSAndroid Build Coastguard Worker ``` 31*c8dee2aaSAndroid Build Coastguard Worker 32*c8dee2aaSAndroid Build Coastguard Worker This macro is similar to 33*c8dee2aaSAndroid Build Coastguard Worker https://github.com/bazelbuild/rules_rust/blob/937e63399b111a6d7ee53b187e4d113300b089e9/rust/private/utils.bzl#L386. 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker Args: 36*c8dee2aaSAndroid Build Coastguard Worker string: A multiline string. 37*c8dee2aaSAndroid Build Coastguard Worker Returns: 38*c8dee2aaSAndroid Build Coastguard Worker The input string minus any indentation. 39*c8dee2aaSAndroid Build Coastguard Worker """ 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker def get_indentation(line): 42*c8dee2aaSAndroid Build Coastguard Worker indentation = "" 43*c8dee2aaSAndroid Build Coastguard Worker for char in line.elems(): 44*c8dee2aaSAndroid Build Coastguard Worker if char in [" ", "\t"]: 45*c8dee2aaSAndroid Build Coastguard Worker indentation += char 46*c8dee2aaSAndroid Build Coastguard Worker else: 47*c8dee2aaSAndroid Build Coastguard Worker break 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker # For some reason Buildifier thinks the below variable is uninitialized. 50*c8dee2aaSAndroid Build Coastguard Worker # buildifier: disable=uninitialized 51*c8dee2aaSAndroid Build Coastguard Worker return indentation 52*c8dee2aaSAndroid Build Coastguard Worker 53*c8dee2aaSAndroid Build Coastguard Worker lines = string.split("\n") 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker # Skip first line if empty. 56*c8dee2aaSAndroid Build Coastguard Worker if get_indentation(lines[0]) == lines[0]: 57*c8dee2aaSAndroid Build Coastguard Worker lines = lines[1:] 58*c8dee2aaSAndroid Build Coastguard Worker 59*c8dee2aaSAndroid Build Coastguard Worker # Compute indentation based on the first remaining line, and remove indentation from all lines. 60*c8dee2aaSAndroid Build Coastguard Worker indentation = get_indentation(lines[0]) 61*c8dee2aaSAndroid Build Coastguard Worker lines = [line.removeprefix(indentation) for line in lines] 62*c8dee2aaSAndroid Build Coastguard Worker 63*c8dee2aaSAndroid Build Coastguard Worker # Skip last line if empty. 64*c8dee2aaSAndroid Build Coastguard Worker if get_indentation(lines[len(lines) - 1]) == lines[len(lines) - 1]: 65*c8dee2aaSAndroid Build Coastguard Worker lines = lines[:-1] 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker result = "\n".join(lines) 68*c8dee2aaSAndroid Build Coastguard Worker if result[:-1] != "\n": 69*c8dee2aaSAndroid Build Coastguard Worker # Ensure we always end with a newline. 70*c8dee2aaSAndroid Build Coastguard Worker result += "\n" 71*c8dee2aaSAndroid Build Coastguard Worker 72*c8dee2aaSAndroid Build Coastguard Worker return result 73