1# Copyright 2018 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"""Transform contains data transformation methods.""" 15 16load(":constants.bzl", "constants") 17load(":utils.bzl", "utils") 18load("//rules/flags:flags.bzl", _flags = "flags") 19 20def _declare_file(ctx, filename, sibling = None): 21 return utils.isolated_declare_file(ctx, filename, sibling = sibling) 22 23def filter_jars(name, data): 24 """Filters out files that are not compiled Jars - includes header Jars. 25 26 Args: 27 name: Name of the file to filter, check uses endswith on the path. 28 data: The list of tuples where each entry contains the originating file path 29 and file to apply the filter. 30 31 Returns: 32 A list of tuples where each entry contains the originating Jar path and the 33 Jar file. 34 """ 35 return [jar for jar in data if not jar.path.endswith(name)] 36 37def dex( 38 ctx, 39 data, 40 deps = constants.EMPTY_LIST, 41 num_shards = None, 42 create_file = _declare_file, 43 desugar = True): 44 """Dex a list of Jars. 45 46 Args: 47 ctx: The context. 48 data: The list of tuples where each entry contains the originating Jar 49 path and the Jar to Dex. 50 deps: The list of dependencies for the Jar being desugared. 51 num_shards: The number of shards to distribute the dexed files across, 52 this value overrides the default provided by ctx.attr._mi_dex_shards. 53 create_file: In rare occasions a custom method is required to 54 create a unique file, override the default here. The method must 55 implement the following interface: 56 57 def create_file(ctx, filename, sibling = None) 58 Args: 59 ctx: The context. 60 filename: string. The name of the file. 61 sibling: File. The location of the new file. 62 63 Returns: 64 A File. 65 desugar: A boolean that determines whether to apply desugaring. 66 67 Returns: 68 A list of tuples where each entry contains the originating Jar path and 69 the Dex shards. 70 """ 71 if num_shards: 72 num_dex_shards = num_shards 73 elif _flags.get(ctx).use_custom_dex_shards: 74 num_dex_shards = _flags.get(ctx).num_dex_shards 75 else: 76 num_dex_shards = ctx.attr._mi_dex_shards 77 78 dex_files = [] 79 for jar in data: 80 out_dex_shards = [] 81 dirname = jar.basename + "_dex" 82 for i in range(num_shards or num_dex_shards): 83 out_dex_shards.append(create_file( 84 ctx, 85 dirname + "/" + str(i) + ".zip", 86 sibling = jar, 87 )) 88 utils.dex(ctx, jar, out_dex_shards, deps, desugar) 89 dex_files.append(out_dex_shards) 90 return dex_files 91 92def extract_jar_resources(ctx, data, create_file = _declare_file): 93 """Extracts the non-class files from the list of Jars. 94 95 Args: 96 ctx: The context 97 data: The list of tuples where each entry contains the originating Jar 98 path and the Jar with resources to extract. 99 create_file: In rare occasions a custom method is required to 100 create a unique file, override the default here. The method must 101 implement the following interface: 102 103 def create_file(ctx, filename, sibling = None) 104 Args: 105 ctx: The context. 106 filename: string. The name of the file. 107 sibling: File. The location of the new file. 108 109 Returns: 110 A File. 111 112 Returns: 113 A list of extracted resource zips. 114 """ 115 resources_files = [] 116 for jar in data: 117 out_resources_file = create_file( 118 ctx, 119 jar.basename + "_resources.zip", 120 sibling = jar, 121 ) 122 utils.extract_jar_resources(ctx, jar, out_resources_file) 123 resources_files.append(out_resources_file) 124 return resources_files 125 126def merge_dex_shards(ctx, data, sibling): 127 """Merges all dex files in the transitive deps to a dex per shard. 128 129 Given a list of dex files (and resources.zips) this will create an 130 action per shard that runs dex_shard_merger on all dex files within that 131 shard. 132 133 Arguments: 134 ctx: The context. 135 data: A list of lists, where the inner list contains dex shards. 136 sibling: A file used to root the merged_dex shards. 137 138 Returns: 139 A list of merged dex shards. 140 """ 141 merged_dex_shards = [] 142 for idx, shard in enumerate(data): 143 # To ensure resource is added at the beginning, R.zip is named as 00.zip 144 # Thus data shards starts from 1 instead of 0 and ranges through 16 145 idx += 1 146 147 # Shards are sorted before deployment, to ensure all shards are correctly 148 # ordered 0 is padded to single digit shard counts 149 shard_name = "%s%s" % ("00"[len(str(idx)):], idx) 150 merged_dex_shard = utils.isolated_declare_file( 151 ctx, 152 "dex_shards/" + shard_name + ".zip", 153 sibling = sibling, 154 ) 155 utils.merge_dex_shards(ctx, shard, merged_dex_shard) 156 merged_dex_shards.append(merged_dex_shard) 157 return merged_dex_shards 158