aboutsummaryrefslogtreecommitdiff
path: root/pkg/private/util.bzl
blob: 7d36cf8e0d0c4edb68a8ce54e424edde4d73ed11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Internal utilities for rules_pkg."""

load("//pkg:providers.bzl", "PackageVariablesInfo")

def setup_output_files(ctx, package_file_name = None, default_output_file = None):
    """Provide output file metadata for common packaging rules

    By default, this will instruct rules to write directly to the File specified
    by the `default_output_file` argument or `ctx.outputs.out` otherwise.

    If `package_file_name` is given, or is available in `ctx`, we will write to
    that name instead, do substitution via `ctx.attr.package_variables`, and the
    default output (either by `default_output_file` or `ctx.outputs.out`) will
    be a symlink to it.

    Callers should:
       - write to `output_file`
       - add `outputs` to their returned `DefaultInfo(files)` provider
       - Possibly add a distinguishing element to OutputGroups

    Args:
      ctx: rule context
      package_file_name: computed value for package_file_name
      default_output_file: File identifying the rule's default output, otherwise `ctx.outputs.out` will be used instead.

    Returns:
      outputs: list(output handles)
      output_file: file handle to write to
      output_name: name of output file

    """
    default_output = default_output_file or ctx.outputs.out

    outputs = [default_output]
    if not package_file_name:
        package_file_name = ctx.attr.package_file_name
    if package_file_name:
        output_name = substitute_package_variables(ctx, package_file_name)
        output_file = ctx.actions.declare_file(output_name)
        outputs.append(output_file)
        ctx.actions.symlink(
            output = default_output,
            target_file = output_file,
        )
    else:
        output_file = default_output
        output_name = output_file.basename
    return outputs, output_file, output_name

def substitute_package_variables(ctx, attribute_value):
    """Substitute package_variables in the attribute with the given name.

    Args:
      ctx: context
      attribute_value: the name of the attribute to perform package_variables substitution for

    Returns:
      expanded_attribute_value: new value of the attribute after package_variables substitution
    """
    if not attribute_value:
        return attribute_value

    if type(attribute_value) != "string":
        fail("attempt to substitute package_variables in the attribute value %s which is not a string" % attribute_value)
    vars = dict(ctx.var)
    if ctx.attr.package_variables:
        package_variables = ctx.attr.package_variables[PackageVariablesInfo]
        vars.update(package_variables.values)

    # Map $(var) to {x} and then use format for substitution.
    # This is brittle and I hate it. We should have template substitution
    # in the Starlark runtime.
    return attribute_value.replace("$(", "{").replace(")", "}").format(**vars)