xref: /aosp_15_r20/external/bazelbuild-rules_android/mobile_install/transform.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
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