Skip to content

Commit de6159d

Browse files
committed
v0 of our multi-rpm generator
1 parent c5573c0 commit de6159d

File tree

4 files changed

+244
-16
lines changed

4 files changed

+244
-16
lines changed

pkg/make_rpm.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,9 @@ def Cleanup():
8282

8383
def FindOutputFile(log):
8484
"""Find the written file from the log information."""
85-
86-
m = WROTE_FILE_RE.search(log)
85+
m = WROTE_FILE_RE.findall(log)
8786
if m:
88-
return m.group('rpm_path')
87+
return m
8988
return None
9089

9190
def SlurpFile(input_path):
@@ -188,7 +187,7 @@ def __init__(self, name, version, release, arch, rpmbuild_path,
188187
self.arch = arch
189188
self.files = []
190189
self.rpmbuild_path = FindRpmbuild(rpmbuild_path)
191-
self.rpm_path = None
190+
self.rpm_paths = None
192191
self.source_date_epoch = helpers.GetFlagValue(source_date_epoch)
193192
self.debug = debug
194193

@@ -205,6 +204,7 @@ def __init__(self, name, version, release, arch, rpmbuild_path,
205204
self.post_scriptlet = None
206205
self.preun_scriptlet = None
207206
self.postun_scriptlet = None
207+
self.subpackages = None
208208

209209
def AddFiles(self, paths, root=''):
210210
"""Add a set of files to the current RPM.
@@ -228,6 +228,7 @@ def SetupWorkdir(self,
228228
preamble_file=None,
229229
description_file=None,
230230
install_script_file=None,
231+
subpackages_file=None,
231232
pre_scriptlet_path=None,
232233
post_scriptlet_path=None,
233234
preun_scriptlet_path=None,
@@ -269,6 +270,8 @@ def SetupWorkdir(self,
269270
SlurpFile(os.path.join(original_dir, preun_scriptlet_path)) if preun_scriptlet_path is not None else ''
270271
self.postun_scriptlet = \
271272
SlurpFile(os.path.join(original_dir, postun_scriptlet_path)) if postun_scriptlet_path is not None else ''
273+
self.subpackages = \
274+
SlurpFile(os.path.join(original_dir, subpackages_file)) if subpackages_file is not None else ''
272275

273276
# Then prepare for textual substitution. This is typically only the case for the
274277
# experimental `pkg_rpm`.
@@ -277,6 +280,7 @@ def SetupWorkdir(self,
277280
'POST_SCRIPTLET': ("%post\n" + self.post_scriptlet) if self.post_scriptlet else "",
278281
'PREUN_SCRIPTLET': ("%preun\n" + self.preun_scriptlet) if self.preun_scriptlet else "",
279282
'POSTUN_SCRIPTLET': ("%postun\n" + self.postun_scriptlet) if self.postun_scriptlet else "",
283+
'SUBPACKAGES' : (self.subpackages if self.subpackages else ""),
280284
'CHANGELOG': ""
281285
}
282286

@@ -406,9 +410,9 @@ def CallRpmBuild(self, dirname, rpmbuild_args):
406410

407411
if p.returncode == 0:
408412
# Find the created file.
409-
self.rpm_path = FindOutputFile(output)
413+
self.rpm_paths = FindOutputFile(output)
410414

411-
if p.returncode != 0 or not self.rpm_path:
415+
if p.returncode != 0 or not self.rpm_paths:
412416
print('Error calling rpmbuild:')
413417
print(output)
414418
elif self.debug:
@@ -417,20 +421,33 @@ def CallRpmBuild(self, dirname, rpmbuild_args):
417421
# Return the status.
418422
return p.returncode
419423

420-
def SaveResult(self, out_file):
424+
def SaveResult(self, out_file, subpackage_out_files):
421425
"""Save the result RPM out of the temporary working directory."""
422426

423-
if self.rpm_path:
424-
shutil.copy(self.rpm_path, out_file)
427+
if self.rpm_paths:
428+
rpm_path = self.rpm_paths[0]
429+
shutil.copy(rpm_path, out_file)
425430
if self.debug:
426431
print('Saved RPM file to %s' % out_file)
432+
433+
subrpm_paths = self.rpm_paths[1:]
434+
for s_name, s_out_file in subpackage_out_files:
435+
s_prefix = self.name + '-' + s_name
436+
437+
for p in subrpm_paths:
438+
if os.path.basename(p).startswith(s_prefix):
439+
shutil.copy(p, s_out_file)
440+
if self.debug:
441+
print('Saved %s sub RPM file to %s' % (s_name, s_out_file))
442+
break
427443
else:
428444
print('No RPM file created.')
429445

430-
def Build(self, spec_file, out_file,
446+
def Build(self, spec_file, out_file, subpackage_out_files,
431447
preamble_file=None,
432448
description_file=None,
433449
install_script_file=None,
450+
subpackages_file=None,
434451
pre_scriptlet_path=None,
435452
post_scriptlet_path=None,
436453
preun_scriptlet_path=None,
@@ -446,20 +463,24 @@ def Build(self, spec_file, out_file,
446463
original_dir = os.getcwd()
447464
spec_file = os.path.join(original_dir, spec_file)
448465
out_file = os.path.join(original_dir, out_file)
466+
subpackage_out_files = (s.split(':') for s in subpackage_out_files)
467+
subpackage_out_files = [
468+
(s[0], os.path.join(original_dir, s[1])) for s in subpackage_out_files]
449469
with Tempdir() as dirname:
450470
self.SetupWorkdir(spec_file,
451471
original_dir,
452472
preamble_file=preamble_file,
453473
description_file=description_file,
454474
install_script_file=install_script_file,
475+
subpackages_file=subpackages_file,
455476
file_list_path=file_list_path,
456477
pre_scriptlet_path=pre_scriptlet_path,
457478
post_scriptlet_path=post_scriptlet_path,
458479
preun_scriptlet_path=preun_scriptlet_path,
459480
postun_scriptlet_path=postun_scriptlet_path,
460481
changelog_file=changelog_file)
461482
status = self.CallRpmBuild(dirname, rpmbuild_args or [])
462-
self.SaveResult(out_file)
483+
self.SaveResult(out_file, subpackage_out_files)
463484

464485
return status
465486

@@ -482,6 +503,9 @@ def main(argv):
482503
help='The file containing the RPM specification.')
483504
parser.add_argument('--out_file', required=True,
484505
help='The destination to save the resulting RPM file to.')
506+
parser.add_argument('--subpackage_out_file', action='append',
507+
help='List of destinations to save resulting ' +
508+
'subpackage RPMs to in the form of name:destination')
485509
parser.add_argument('--rpmbuild', help='Path to rpmbuild executable.')
486510
parser.add_argument('--source_date_epoch',
487511
help='Value for the SOURCE_DATE_EPOCH rpmbuild '
@@ -498,6 +522,8 @@ def main(argv):
498522
help='File containing the RPM Preamble')
499523
parser.add_argument('--description',
500524
help='File containing the RPM %description text')
525+
parser.add_argument('--subpackages',
526+
help='File containing the RPM subpackage details')
501527
parser.add_argument('--pre_scriptlet',
502528
help='File containing the RPM %pre scriptlet, if to be substituted')
503529
parser.add_argument('--post_scriptlet',
@@ -528,9 +554,11 @@ def main(argv):
528554
debug=options.debug)
529555
builder.AddFiles(options.files)
530556
return builder.Build(options.spec_file, options.out_file,
557+
options.subpackage_out_file,
531558
preamble_file=options.preamble,
532559
description_file=options.description,
533560
install_script_file=options.install_script,
561+
subpackages_file=options.subpackages,
534562
file_list_path=options.file_list,
535563
pre_scriptlet_path=options.pre_scriptlet,
536564
post_scriptlet_path=options.post_scriptlet,

pkg/rpm/template.spec.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ ${PREUN_SCRIPTLET}
1919

2020
${POSTUN_SCRIPTLET}
2121

22+
${SUBPACKAGES}
23+
2224
${CHANGELOG}

pkg/rpm_pfg.bzl

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ load(
3333
"PackageSymlinkInfo",
3434
"PackageVariablesInfo",
3535
)
36+
load(
37+
"//pkg:rpm_providers.bzl",
38+
"SubRPMInfo",
39+
)
3640
load("//pkg/private:util.bzl", "setup_output_files", "substitute_package_variables")
3741

3842
rpm_filetype = [".rpm"]
@@ -285,6 +289,54 @@ def _process_dep(dep, process_ctx):
285289
process_ctx,
286290
)
287291

292+
def _process_subpackage(rpm_info):
293+
process_ctx = struct(
294+
dest_check_map = {},
295+
install_script_pieces = [],
296+
packaged_directories = [],
297+
rpm_files_list = [],
298+
)
299+
300+
rpm_lines = [
301+
"%%package %s" % rpm_info.package_name,
302+
"Summary: %s" % rpm_info.summary,
303+
]
304+
305+
if rpm_info.architecture:
306+
rpm_lines += [ "BuildArch: %s" % rpm_info.architecture ]
307+
308+
if rpm_info.version:
309+
rpm_lines += [ "Version: %s" % rpm_info.version ]
310+
311+
for r in rpm_info.requires:
312+
rpm_lines += [ "Requires: %s" % r ]
313+
314+
rpm_lines += [
315+
"",
316+
"%%description %s" % rpm_info.package_name,
317+
rpm_info.description,
318+
]
319+
320+
if rpm_info.post_scriptlet:
321+
rpm_lines += [
322+
"",
323+
"%%post %s" % rpm_info.package_name,
324+
]
325+
326+
if rpm_info.srcs:
327+
rpm_lines += [
328+
"",
329+
"%%files %s" % rpm_info.package_name,
330+
]
331+
332+
for dep in rpm_info.srcs:
333+
_process_dep(dep, process_ctx)
334+
335+
rpm_lines += process_ctx.rpm_files_list
336+
rpm_lines += [""]
337+
338+
return rpm_lines, process_ctx.install_script_pieces, process_ctx.packaged_directories
339+
288340
#### Rule implementation
289341

290342
def _pkg_rpm_impl(ctx):
@@ -338,12 +390,14 @@ def _pkg_rpm_impl(ctx):
338390
ctx.attr.architecture,
339391
)
340392

341-
outputs, output_file, output_name = setup_output_files(
393+
outputs, output_file, _ = setup_output_files(
342394
ctx,
343395
package_file_name = package_file_name,
344396
default_output_file = default_file,
345397
)
346398

399+
output_rpm_files = [output_file]
400+
347401
#### rpm spec "preamble"
348402
preamble_pieces = []
349403

@@ -523,7 +577,7 @@ def _pkg_rpm_impl(ctx):
523577
args.append("--out_file=" + output_file.path)
524578

525579
# Add data files
526-
files += ctx.files.srcs
580+
files += ctx.files.srcs + ctx.files.subpackages
527581

528582
#### Consistency checking; input processing
529583

@@ -563,6 +617,54 @@ def _pkg_rpm_impl(ctx):
563617
for dep in ctx.attr.srcs:
564618
_process_dep(dep, process_ctx)
565619

620+
#### subpackages
621+
subpackage_file = ctx.actions.declare_file(
622+
"{}.spec.subpackages".format(rpm_name),
623+
)
624+
if ctx.attr.subpackages:
625+
subpackage_lines = []
626+
627+
for s in ctx.attr.subpackages:
628+
s_rpm_info = s[SubRPMInfo]
629+
s_lines, s_install_script_pieces, s_packaged_directories = _process_subpackage(s_rpm_info)
630+
631+
subpackage_lines += s_lines
632+
install_script_pieces += s_install_script_pieces
633+
packaged_directories += s_packaged_directories
634+
635+
s_package_file_name = "%s-%s-%s-%s.%s.rpm" % (
636+
rpm_name,
637+
s_rpm_info.package_name,
638+
s_rpm_info.version or ctx.attr.version,
639+
ctx.attr.release,
640+
s_rpm_info.architecture or ctx.attr.architecture,
641+
)
642+
643+
s_default_file = ctx.actions.declare_file("{}-{}.rpm".format(rpm_name, s_rpm_info.package_name))
644+
s_outputs, s_output_file, _ = setup_output_files(
645+
ctx,
646+
package_file_name = s_package_file_name,
647+
default_output_file = s_default_file,
648+
)
649+
650+
outputs += s_outputs
651+
output_rpm_files.append(s_output_file)
652+
653+
args += [ "--subpackage_out_file=%s:%s" % (
654+
s_rpm_info.package_name, s_output_file.path) ]
655+
656+
ctx.actions.write(
657+
output = subpackage_file,
658+
content = "\n".join(subpackage_lines),
659+
)
660+
else:
661+
ctx.actions.write(
662+
output = subpackage_file,
663+
content = "# no subpackages",
664+
)
665+
files.append(subpackage_file)
666+
args.append("--subpackages=" + subpackage_file.path)
667+
566668
#### Procedurally-generated scripts/lists (%install, %files)
567669

568670
# We need to write these out regardless of whether we are using
@@ -641,7 +743,7 @@ def _pkg_rpm_impl(ctx):
641743

642744
args.extend(["--rpmbuild_arg=" + a for a in additional_rpmbuild_args])
643745

644-
for f in ctx.files.srcs:
746+
for f in ctx.files.srcs + ctx.files.subpackages:
645747
args.append(f.path)
646748

647749
#### Call the generator script.
@@ -652,7 +754,7 @@ def _pkg_rpm_impl(ctx):
652754
use_default_shell_env = True,
653755
arguments = args,
654756
inputs = files,
655-
outputs = [output_file],
757+
outputs = output_rpm_files,
656758
env = {
657759
"LANG": "en_US.UTF-8",
658760
"LC_CTYPE": "UTF-8",
@@ -668,7 +770,7 @@ def _pkg_rpm_impl(ctx):
668770

669771
output_groups = {
670772
"out": [default_file],
671-
"rpm": [output_file],
773+
"rpm": output_rpm_files,
672774
"changes": changes
673775
}
674776
return [
@@ -1012,6 +1114,12 @@ pkg_rpm = rule(
10121114
overcommitting your system.
10131115
""",
10141116
),
1117+
"subpackages": attr.label_list(
1118+
doc = """Subpackages to build with this RPM""",
1119+
providers = [
1120+
[SubRPMInfo],
1121+
],
1122+
),
10151123
"rpmbuild_path": attr.string(
10161124
doc = """Path to a `rpmbuild` binary. Deprecated in favor of the rpmbuild toolchain""",
10171125
),

0 commit comments

Comments
 (0)