xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/processing_pipeline.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1*9e965d6fSRomain Jobredeaux# Copyright 2020 The Bazel Authors. All rights reserved.
2*9e965d6fSRomain Jobredeaux#
3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License");
4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License.
5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at
6*9e965d6fSRomain Jobredeaux#
7*9e965d6fSRomain Jobredeaux#    http://www.apache.org/licenses/LICENSE-2.0
8*9e965d6fSRomain Jobredeaux#
9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software
10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS,
11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and
13*9e965d6fSRomain Jobredeaux# limitations under the License.
14*9e965d6fSRomain Jobredeaux
15*9e965d6fSRomain Jobredeaux"""Common implementation for processing pipelines."""
16*9e965d6fSRomain Jobredeaux
17*9e965d6fSRomain JobredeauxPROVIDERS = "providers"
18*9e965d6fSRomain JobredeauxVALIDATION_OUTPUTS = "validation_outputs"
19*9e965d6fSRomain Jobredeaux
20*9e965d6fSRomain Jobredeaux# TODO(djwhang): When a provider type can be retrieved from a Starlark provider
21*9e965d6fSRomain Jobredeaux# ProviderInfo is necessary. Once this is possible, processor methods can have a
22*9e965d6fSRomain Jobredeaux# uniform method signature foo(ctx, target_ctx) where we can pull the provider
23*9e965d6fSRomain Jobredeaux# off the target_ctx using the provider type.
24*9e965d6fSRomain Jobredeaux#
25*9e965d6fSRomain Jobredeaux# Yes, this effectively leads to producing a build rule like system within a
26*9e965d6fSRomain Jobredeaux# build rule, rather than resorting to rule based composition.
27*9e965d6fSRomain JobredeauxProviderInfo = provider(
28*9e965d6fSRomain Jobredeaux    "Stores metadata about the actual Starlark provider returned.",
29*9e965d6fSRomain Jobredeaux    fields = dict(
30*9e965d6fSRomain Jobredeaux        name = "The type of the provider",
31*9e965d6fSRomain Jobredeaux        value = "The actual provider",
32*9e965d6fSRomain Jobredeaux        runfiles = "Runfiles to pass to the DefaultInfo provider",
33*9e965d6fSRomain Jobredeaux    ),
34*9e965d6fSRomain Jobredeaux)
35*9e965d6fSRomain Jobredeaux
36*9e965d6fSRomain Jobredeaux_ProcessingPipelineInfo = provider(
37*9e965d6fSRomain Jobredeaux    "Stores functions that forms a rule's implementation.",
38*9e965d6fSRomain Jobredeaux    fields = dict(
39*9e965d6fSRomain Jobredeaux        processors = "Ordered dictionary of processing functions.",
40*9e965d6fSRomain Jobredeaux        finalize = "Function to form the final providers to propagate.",
41*9e965d6fSRomain Jobredeaux    ),
42*9e965d6fSRomain Jobredeaux)
43*9e965d6fSRomain Jobredeaux
44*9e965d6fSRomain Jobredeauxdef _make_processing_pipeline(processors = dict(), finalize = None):
45*9e965d6fSRomain Jobredeaux    """Creates the combined processing pipeline.
46*9e965d6fSRomain Jobredeaux
47*9e965d6fSRomain Jobredeaux    Args:
48*9e965d6fSRomain Jobredeaux      processors: Ordered dictionary of processing functions.
49*9e965d6fSRomain Jobredeaux      finalize: Function to form the final providers to propagate.
50*9e965d6fSRomain Jobredeaux
51*9e965d6fSRomain Jobredeaux    Returns:
52*9e965d6fSRomain Jobredeaux      A _ProcessingPipelineInfo provider.
53*9e965d6fSRomain Jobredeaux    """
54*9e965d6fSRomain Jobredeaux    return _ProcessingPipelineInfo(
55*9e965d6fSRomain Jobredeaux        processors = processors,
56*9e965d6fSRomain Jobredeaux        finalize = finalize,
57*9e965d6fSRomain Jobredeaux    )
58*9e965d6fSRomain Jobredeaux
59*9e965d6fSRomain Jobredeauxdef _run(ctx, java_package, processing_pipeline):
60*9e965d6fSRomain Jobredeaux    """Runs the processing pipeline and populates the target context.
61*9e965d6fSRomain Jobredeaux
62*9e965d6fSRomain Jobredeaux    Args:
63*9e965d6fSRomain Jobredeaux      ctx: The context.
64*9e965d6fSRomain Jobredeaux      java_package: The java package resolved from the target's path
65*9e965d6fSRomain Jobredeaux        or the custom_package attr.
66*9e965d6fSRomain Jobredeaux      processing_pipeline: The _ProcessingPipelineInfo provider for this target.
67*9e965d6fSRomain Jobredeaux
68*9e965d6fSRomain Jobredeaux    Returns:
69*9e965d6fSRomain Jobredeaux      The output of the _ProcessingPipelineInfo.finalize function.
70*9e965d6fSRomain Jobredeaux    """
71*9e965d6fSRomain Jobredeaux    target_ctx = dict(
72*9e965d6fSRomain Jobredeaux        java_package = java_package,
73*9e965d6fSRomain Jobredeaux        providers = [],
74*9e965d6fSRomain Jobredeaux        validation_outputs = [],
75*9e965d6fSRomain Jobredeaux        runfiles = ctx.runfiles(),
76*9e965d6fSRomain Jobredeaux    )
77*9e965d6fSRomain Jobredeaux
78*9e965d6fSRomain Jobredeaux    for execute in processing_pipeline.processors.values():
79*9e965d6fSRomain Jobredeaux        info = execute(ctx, **target_ctx)
80*9e965d6fSRomain Jobredeaux        if info:
81*9e965d6fSRomain Jobredeaux            if info.name in target_ctx:
82*9e965d6fSRomain Jobredeaux                fail("%s provider already registered in target context" % info.name)
83*9e965d6fSRomain Jobredeaux            target_ctx[info.name] = info.value
84*9e965d6fSRomain Jobredeaux            target_ctx[PROVIDERS].extend(getattr(info.value, PROVIDERS, []))
85*9e965d6fSRomain Jobredeaux            target_ctx[VALIDATION_OUTPUTS].extend(getattr(info.value, VALIDATION_OUTPUTS, []))
86*9e965d6fSRomain Jobredeaux            if hasattr(info, "runfiles") and info.runfiles:
87*9e965d6fSRomain Jobredeaux                target_ctx["runfiles"] = target_ctx["runfiles"].merge(info.runfiles)
88*9e965d6fSRomain Jobredeaux
89*9e965d6fSRomain Jobredeaux    return processing_pipeline.finalize(ctx, **target_ctx)
90*9e965d6fSRomain Jobredeaux
91*9e965d6fSRomain Jobredeauxdef _prepend(processors, **new_processors):
92*9e965d6fSRomain Jobredeaux    """Prepends processors in a given processing pipeline.
93*9e965d6fSRomain Jobredeaux
94*9e965d6fSRomain Jobredeaux    Args:
95*9e965d6fSRomain Jobredeaux      processors: The dictionary representing the processing pipeline.
96*9e965d6fSRomain Jobredeaux      **new_processors: The processors to add where the key represents the
97*9e965d6fSRomain Jobredeaux        name of the processor and value is the function pointer to the new
98*9e965d6fSRomain Jobredeaux        processor.
99*9e965d6fSRomain Jobredeaux
100*9e965d6fSRomain Jobredeaux    Returns:
101*9e965d6fSRomain Jobredeaux      A dictionary which represents the new processing pipeline.
102*9e965d6fSRomain Jobredeaux    """
103*9e965d6fSRomain Jobredeaux    updated_processors = dict()
104*9e965d6fSRomain Jobredeaux    for name, processor in new_processors.items():
105*9e965d6fSRomain Jobredeaux        updated_processors[name] = processor
106*9e965d6fSRomain Jobredeaux
107*9e965d6fSRomain Jobredeaux    for key in processors.keys():
108*9e965d6fSRomain Jobredeaux        updated_processors[key] = processors[key]
109*9e965d6fSRomain Jobredeaux
110*9e965d6fSRomain Jobredeaux    return updated_processors
111*9e965d6fSRomain Jobredeaux
112*9e965d6fSRomain Jobredeauxdef _append(processors, **new_processors):
113*9e965d6fSRomain Jobredeaux    """Appends processors in a given processing pipeline.
114*9e965d6fSRomain Jobredeaux
115*9e965d6fSRomain Jobredeaux    Args:
116*9e965d6fSRomain Jobredeaux      processors: The dictionary representing the processing pipeline.
117*9e965d6fSRomain Jobredeaux      **new_processors: The processors to append where the key represents the
118*9e965d6fSRomain Jobredeaux        name of the processor and value is the function pointer to the new
119*9e965d6fSRomain Jobredeaux        processor.
120*9e965d6fSRomain Jobredeaux
121*9e965d6fSRomain Jobredeaux    Returns:
122*9e965d6fSRomain Jobredeaux      A dictionary which represents the new processing pipeline.
123*9e965d6fSRomain Jobredeaux    """
124*9e965d6fSRomain Jobredeaux    updated_processors = dict(processors)
125*9e965d6fSRomain Jobredeaux    for name, processor in new_processors.items():
126*9e965d6fSRomain Jobredeaux        updated_processors[name] = processor
127*9e965d6fSRomain Jobredeaux
128*9e965d6fSRomain Jobredeaux    return updated_processors
129*9e965d6fSRomain Jobredeaux
130*9e965d6fSRomain Jobredeauxdef _replace(processors, **new_processors):
131*9e965d6fSRomain Jobredeaux    """Replace processors in a given processing pipeline.
132*9e965d6fSRomain Jobredeaux
133*9e965d6fSRomain Jobredeaux    Args:
134*9e965d6fSRomain Jobredeaux      processors: The dictionary representing the processing pipeline.
135*9e965d6fSRomain Jobredeaux      **new_processors: The processors to override where the key represents the
136*9e965d6fSRomain Jobredeaux        name of the processor and value is the function pointer to the new
137*9e965d6fSRomain Jobredeaux        processor.
138*9e965d6fSRomain Jobredeaux
139*9e965d6fSRomain Jobredeaux    Returns:
140*9e965d6fSRomain Jobredeaux      A dictionary which represents the new processing pipeline.
141*9e965d6fSRomain Jobredeaux    """
142*9e965d6fSRomain Jobredeaux    updated_processors = dict(processors)
143*9e965d6fSRomain Jobredeaux    for name, processor in new_processors.items():
144*9e965d6fSRomain Jobredeaux        if name not in processors:
145*9e965d6fSRomain Jobredeaux            fail("Error, %s not found, unable to override." % name)
146*9e965d6fSRomain Jobredeaux
147*9e965d6fSRomain Jobredeaux        # NOTE: Overwriting an existing value does not break iteration order.
148*9e965d6fSRomain Jobredeaux        # However, if a new processor is being added that needs to be injected
149*9e965d6fSRomain Jobredeaux        # between other processors, the processing pipeline dictionary will need
150*9e965d6fSRomain Jobredeaux        # to be recreated.
151*9e965d6fSRomain Jobredeaux        updated_processors[name] = processor
152*9e965d6fSRomain Jobredeaux
153*9e965d6fSRomain Jobredeaux    return updated_processors
154*9e965d6fSRomain Jobredeaux
155*9e965d6fSRomain Jobredeauxprocessing_pipeline = struct(
156*9e965d6fSRomain Jobredeaux    make_processing_pipeline = _make_processing_pipeline,
157*9e965d6fSRomain Jobredeaux    run = _run,
158*9e965d6fSRomain Jobredeaux    prepend = _prepend,
159*9e965d6fSRomain Jobredeaux    append = _append,
160*9e965d6fSRomain Jobredeaux    replace = _replace,
161*9e965d6fSRomain Jobredeaux)
162