aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/build_defs/pkg/rpm.bzl
blob: f3e006429c0ff33db0e72b8a0963159ddce4fcc6 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# Copyright 2017 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.
"""Rules to create RPM archives."""

rpm_filetype = [".rpm"]

spec_filetype = [".spec"]

def _pkg_rpm_impl(ctx):
    """Implements to pkg_rpm rule."""

    files = []
    args = ["--name=" + ctx.label.name]

    # Version can be specified by a file or inlined.
    if ctx.attr.version_file:
        if ctx.attr.version:
            fail("Both version and version_file attributes were specified")
        args += ["--version=@" + ctx.file.version_file.path]
        files += [ctx.file.version_file]
    elif ctx.attr.version:
        args += ["--version=" + ctx.attr.version]

    # Release can be specified by a file or inlined.
    if ctx.attr.release_file:
        if ctx.attr.release:
            fail("Both release and release_file attributes were specified")
        args += ["--release=@" + ctx.file.release_file.path]
        files += [ctx.file.release_file]
    elif ctx.attr.release:
        args += ["--release=" + ctx.attr.release]

    if ctx.attr.architecture:
        args += ["--arch=" + ctx.attr.architecture]

    if not ctx.attr.spec_file:
        fail("spec_file was not specified")

    # Expand the spec file template.
    spec_file = ctx.actions.declare_file("%s.spec" % ctx.label.name)

    # Create the default substitutions based on the data files.
    substitutions = {}
    for data_file in ctx.files.data:
        key = "{%s}" % data_file.basename
        substitutions[key] = data_file.path
    ctx.actions.expand_template(
        template = ctx.file.spec_file,
        output = spec_file,
        substitutions = substitutions,
    )
    args += ["--spec_file=" + spec_file.path]
    files += [spec_file]

    args += ["--out_file=" + ctx.outputs.rpm.path]

    # Add data files.
    if ctx.file.changelog:
        files += [ctx.file.changelog]
        args += [ctx.file.changelog.path]
    files += ctx.files.data

    for f in ctx.files.data:
        args += [f.path]

    if ctx.attr.debug:
        args += ["--debug"]

    # Call the generator script.
    # TODO(katre): Generate a source RPM.
    ctx.actions.run(
        executable = ctx.executable._make_rpm,
        use_default_shell_env = True,
        arguments = args,
        inputs = files,
        outputs = [ctx.outputs.rpm],
        mnemonic = "MakeRpm",
    )

    # Link the RPM to the expected output name.
    ctx.actions.run(
        executable = "ln",
        arguments = [
            "-s",
            ctx.outputs.rpm.basename,
            ctx.outputs.out.path,
        ],
        inputs = [ctx.outputs.rpm],
        outputs = [ctx.outputs.out],
    )

    # Link the RPM to the RPM-recommended output name.
    if "rpm_nvra" in dir(ctx.outputs):
        ctx.actions.run(
            executable = "ln",
            arguments = [
                "-s",
                ctx.outputs.rpm.basename,
                ctx.outputs.rpm_nvra.path,
            ],
            inputs = [ctx.outputs.rpm],
            outputs = [ctx.outputs.rpm_nvra],
        )

def _pkg_rpm_outputs(version, release):
    outputs = {
        "out": "%{name}.rpm",
        "rpm": "%{name}-%{architecture}.rpm",
    }

    # The "rpm_nvra" output follows the recommended package naming convention of
    # Name-Version-Release.Arch.rpm
    # See http://ftp.rpm.org/max-rpm/ch-rpm-file-format.html
    if version and release:
        outputs["rpm_nvra"] = "%{name}-%{version}-%{release}.%{architecture}.rpm"

    return outputs

# Define the rule.
pkg_rpm = rule(
    attrs = {
        "spec_file": attr.label(
            mandatory = True,
            allow_files = spec_filetype,
            single_file = True,
        ),
        "architecture": attr.string(default = "all"),
        "version_file": attr.label(
            allow_files = True,
            single_file = True,
        ),
        "version": attr.string(),
        "changelog": attr.label(
            allow_files = True,
            single_file = True,
        ),
        "data": attr.label_list(
            mandatory = True,
            allow_files = True,
        ),
        "release_file": attr.label(allow_files = True, single_file = True),
        "release": attr.string(),
        "debug": attr.bool(default = False),

        # Implicit dependencies.
        "_make_rpm": attr.label(
            default = Label("//tools/build_defs/pkg:make_rpm"),
            cfg = "host",
            executable = True,
            allow_files = True,
        ),
    },
    executable = False,
    outputs = _pkg_rpm_outputs,
    implementation = _pkg_rpm_impl,
)

"""Creates an RPM format package from the data files.

This runs rpmbuild (and requires it to be installed beforehand) to generate
an RPM package based on the spec_file and data attributes.

Two outputs are guaranteed to be produced: "%{name}.rpm", and
"%{name}-%{architecture}.rpm". If the "version" and "release" arguments are
non-empty, a third output will be produced, following the RPM-recommended
N-V-R.A format (Name-Version-Release.Architecture.rpm).

Args:
  spec_file: The RPM spec file to use. If the version or version_file
    attributes are provided, the Version in the spec will be overwritten,
    and likewise behaviour with release and release_file. Any Sources listed
    in the spec file must be provided as data dependencies.
    The base names of data dependencies can be replaced with the actual location
    using "{basename}" syntax.
  version: The version of the package to generate. This will overwrite any
    Version provided in the spec file. Only specify one of version and
    version_file.
  version_file: A file containing the version of the package to generate. This
    will overwrite any Version provided in the spec file. Only specify one of
    version and version_file.
  release: The release of the package to generate. This will overwrite any
    release provided in the spec file. Only specify one of release and
    release_file.
  release_file: A file containing the release of the package to generate. This
    will overwrite any release provided in the spec file. Only specify one of
    release and release_file.
  changelog: A changelog file to include. This will not be written to the spec
    file, which should only list changes to the packaging, not the software itself.
  data: List all files to be included in the package here.
"""