2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-09-30 06:51:18 +00:00

feat(openeuler): build native dependency packages

This commit is contained in:
Vinícius Ferrão
2026-09-21 18:23:51 -03:00
parent a1fde97f2d
commit 0c0dfb787e
20 changed files with 2081 additions and 39 deletions
+1
View File
@@ -0,0 +1 @@
postgresql/postgresql-15.6-openeuler-llvmjit-buildrequires.patch whitespace=-blank-at-eol
+24
View File
@@ -21,6 +21,7 @@ our @EXPORT_OK = qw(
rpm_version rpm_release rpm_sigmd5 rpm_is_signed restamp_release_line
cross_copy_genesis finalize_xcat_dep bump_dep_release_suffix
build_mock_uniqueext
openeuler_build_target openeuler_repo_subdir
);
# install_deps_packages($os_id): the host packages mockbuild-all.pl needs to run at all, for the
@@ -30,6 +31,7 @@ our @EXPORT_OK = qw(
sub install_deps_packages {
my ($os_id) = @_;
$os_id = '' unless defined $os_id;
return (install_deps_packages(''), '/usr/bin/systemd-nspawn') if lc($os_id) eq 'openeuler';
# The perl modules are what actually break a run; the rest is the toolchain the script drives.
return qw(perl perl-File-Slurper perl-IPC-Cmd perl-Parallel-ForkManager perl-Digest-SHA
mock createrepo_c tar findutils rpm rpm-build rpm-sign rpmdevtools gnupg2 wget git)
@@ -46,9 +48,31 @@ sub install_deps_command {
my @pkgs = install_deps_packages($os_id);
return ('zypper', '--non-interactive', 'install', '--no-recommends', @pkgs)
if $os_id =~ /^(?:opensuse|sles|sled)/;
return ('dnf', '--setopt=gpgcheck=1', '--setopt=*.gpgcheck=1', '--setopt=strict=1', '--setopt=install_weak_deps=False', '-y', 'install', @pkgs)
if lc($os_id) eq 'openeuler';
return ('dnf', '-y', 'install', @pkgs);
}
sub openeuler_build_target {
my ($os, $arch) = @_;
return undef unless lc($os->{ID} // '') eq 'openeuler';
my $version = $os->{VERSION} || $os->{VERSION_ID} || '';
if ($version =~ /\A(20|22|24)\.03\s+\(LTS(?:-SP([1-9][0-9]*))?\)\z/) {
$version = "$1.03" . (defined($2) ? "sp$2" : '');
}
my $target = "openeuler-$version-$arch";
openeuler_repo_subdir($target);
return $target;
}
sub openeuler_repo_subdir {
my ($target) = @_;
return undef unless defined($target) && $target =~ /\Aopeneuler-/;
die "Unsupported openEuler build target '$target'\n"
unless $target =~ /\Aopeneuler-((?:20|22|24)\.03(?:sp[1-9][0-9]*)?)-(x86_64|ppc64le)\z/;
return "openeuler$1/$2";
}
# missing_perl_modules(@modules): those that cannot be loaded, in order. The point of --install-deps
# is that the run AFTER it cannot die on a missing module, so the modules are proven by loading
# them, not by trusting the package manager's exit code.
+67 -9
View File
@@ -7,6 +7,11 @@ use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
use POSIX qw(strftime);
use FindBin;
use lib "$FindBin::Bin/..", "$FindBin::Bin/../lib";
use MockBuildUtils qw(openeuler_build_target openeuler_repo_subdir);
use XCAT::BuildUtils qw(digest_file read_lines);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
@@ -46,11 +51,18 @@ die "Run as root (current uid=$>)\n" if $> != 0;
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = resolve_mock_cfg($os_id, '10', $arch);
if (lc($os_id) eq 'openeuler') {
my $os_version = capture(q{bash -lc 'source /etc/os-release; echo "$VERSION"'});
$mock_cfg = openeuler_build_target({ ID => $os_id, VERSION => $os_version }, $arch);
} else {
$mock_cfg = resolve_mock_cfg($os_id, '10', $arch);
}
}
my $native_repo = openeuler_repo_subdir($mock_cfg);
my ($rel) = $mock_cfg =~ /-(\d+)-/;
$rel //= '10';
my $dist_suffix = defined($native_repo) ? '' : ".el$rel";
# --target-arch names the arch of the rpm to produce. It differs from the host arch only for a
# forcearch target (rocky-10-riscv64-xcat on an x86_64 host; see BUILD.md "riscv64").
@@ -58,12 +70,17 @@ $target_arch = $arch if $target_arch eq '';
my %goarch = (x86_64 => 'amd64', aarch64 => 'arm64', ppc64le => 'ppc64le', s390x => 's390x', riscv64 => 'riscv64');
my $cross = $target_arch ne $arch;
die "No GOARCH known for target arch $target_arch\n" if $cross && !exists $goarch{$target_arch};
if (defined($native_repo)) {
my ($native_arch) = $native_repo =~ m{/([^/]+)$};
die "openEuler goconserver requires a native $native_arch builder\n"
if $cross || $arch ne $native_arch;
}
# For the host arch the Go compile happens INSIDE the mock chroot (BuildRequires: golang), so the
# host only fetches the pinned source and drives mock. A forcearch chroot would run that compile
# under qemu, so the cross build instead cross-compiles on the host and packages the result with
# rpmbuild --target.
for my $bin (qw(git rpm), ($cross ? qw(go rpmbuild) : qw(mock))) {
for my $bin (qw(git rpm), (defined($native_repo) ? 'wget' : ()), ($cross ? qw(go rpmbuild) : qw(mock))) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
@@ -83,13 +100,21 @@ unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) {
chomp $SOURCE_DATE_EPOCH;
}
$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/;
if (defined($native_repo)) {
my $native_epoch = defined($build_timestamp) ? $build_timestamp : $ENV{SOURCE_DATE_EPOCH};
if (defined($native_epoch)) {
die "Invalid native build timestamp: $native_epoch\n" unless $native_epoch =~ /\A\d+\z/;
$SOURCE_DATE_EPOCH = $native_epoch;
}
}
$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH;
# goconserver is a CGO-free static Go binary. el8/el9 chroots ship a Go too old to build 0.3.3, so
# always COMPILE in the el10 chroot for this arch (regardless of the target EL), then ship the static
# binary to every EL repo. The Release still carries the target's dist tag (4.el$rel) so each EL repo
# gets a correctly-named, byte-identical rpm.
(my $build_cfg = $mock_cfg) =~ s/-\d+-/-10-/;
my $build_cfg = $mock_cfg;
$build_cfg =~ s/-\d+-/-10-/ unless defined($native_repo);
print_step("Configuration");
print "repo_root: $repo_root\n";
@@ -97,8 +122,8 @@ print "pkg_dir: $pkg_dir\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "mock_cfg: $mock_cfg (target dist tag: el$rel)\n";
print "build_cfg: $build_cfg (el10 -- portable static build for arch $arch)\n" if !$cross;
print "mock_cfg: $mock_cfg (target dist suffix: $dist_suffix)\n";
print "build_cfg: $build_cfg\n" if !$cross;
print "arch: $arch\n";
print "target_arch: $target_arch" . ($cross ? " (GOARCH=$goarch{$target_arch}, rpmbuild --target)" : '') . "\n";
print "version: $version\n";
@@ -121,6 +146,15 @@ run("git -C " . sh_quote($src_dir) . " remote add origin " . sh_quote($go_repo)
run("git -C " . sh_quote($src_dir) . " fetch --depth 1 origin " . sh_quote($go_ref) . " >>$clone_log 2>&1");
run("git -C " . sh_quote($src_dir) . " checkout -q FETCH_HEAD >>$clone_log 2>&1");
my $go_ldflags = '-X main.Version=%{version}';
if (defined($native_repo)) {
my $source_commit = capture("git -C " . sh_quote($src_dir) . " rev-parse --verify 'HEAD^{commit}'");
die "Cannot resolve fetched goconserver commit\n"
if $? != 0 || $source_commit !~ /\A[0-9a-f]{40}\z/;
my $build_time = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime($SOURCE_DATE_EPOCH));
$go_ldflags .= " -X main.Commit=$source_commit -X main.BuildTime=$build_time";
}
# etcd storage backend has broken deps with modern Go modules; xCAT only uses file storage.
unlink "$src_dir/storage/etcd.go";
remove_tree("$src_dir/storage/etcd") if -d "$src_dir/storage/etcd";
@@ -190,6 +224,26 @@ run("tar --sort=name --owner=0 --group=0 --mtime=\@$SOURCE_DATE_EPOCH" .
write_file("$sources_dir/goconserver.service", $service_unit);
write_file("$sources_dir/server.conf", $server_conf);
my ($go_source, $go_prep, $go_environment) = ('', '', '');
my $native_changelog = '';
my $go_requires = 'golang';
if (defined($native_repo)) {
my $go_file = "go1.25.12.linux-$goarch{$arch}.tar.gz";
my %checksums = map { my ($hash, $name) = split /\s+/, $_; ($name, $hash) }
read_lines("$pkg_dir/toolchains/go1.25.12.sha256");
my $go_hash = $checksums{$go_file};
die "No pinned checksum for $go_file\n" unless defined($go_hash) && $go_hash =~ /\A[0-9a-f]{64}\z/;
my $go_url = "https://go.dev/dl/$go_file";
my $go_archive = "$sources_dir/$go_file";
run("wget --https-only --tries=3 --timeout=60 -q -O " . sh_quote($go_archive) . " " . sh_quote($go_url));
die "Go toolchain checksum mismatch: $go_file\n" unless digest_file($go_archive) eq $go_hash;
$go_source = "Source3: $go_url\n";
$go_requires = 'coreutils tar gzip ca-certificates';
$go_prep = "echo '$go_hash %{SOURCE3}' | sha256sum -c -\ntar -C %{_builddir} -xzf %{SOURCE3}\n";
$go_environment = 'export PATH=%{_builddir}/go/bin:$PATH' . "\ngo version\n";
$native_changelog = "* Tue Sep 08 2026 xCAT build - $version-4\n- Build in the native openEuler target with the verified Go 1.25.12 source archive.\n\n";
}
# --- Spec: the Go compile runs in %build INSIDE the chroot; modules fetched from the proxy, pinned by go.sum ---
print_step("Write spec");
my $spec_file = "$work_dir/goconserver.spec";
@@ -199,7 +253,7 @@ write_file($spec_file, <<"SPEC");
%global debug_package %{nil}
Name: goconserver
Version: $version
Release: 4.el$rel$release_suffix
Release: 4$dist_suffix$release_suffix
Summary: Console server written in Go for xCAT
License: EPL-1.0
URL: https://github.com/xcat2/goconserver
@@ -208,8 +262,9 @@ BuildArch: $arch
Source0: goconserver-%{version}.tar.gz
Source1: goconserver.service
Source2: server.conf
$go_source
BuildRequires: golang
BuildRequires: $go_requires
%description
goconserver is a scalable console server written in Go. It provides
@@ -217,15 +272,17 @@ console logging and management for xCAT cluster nodes.
%prep
%setup -q -n goconserver-%{version}
$go_prep
%build
# Compile in-chroot. Modules are downloaded from the Go proxy at build time (mock networking is on)
# but PINNED + integrity-checked by the committed go.sum, so the build is reproducible without a
# vendored tree. GOTOOLCHAIN=local pins the chroot's Go (never auto-downloads a toolchain).
$go_environment
export GOFLAGS=-mod=mod GOTOOLCHAIN=local CGO_ENABLED=0
export GOCACHE=%{_builddir}/.gocache GOPATH=%{_builddir}/.gopath GOMODCACHE=%{_builddir}/.gomodcache
go build -trimpath -buildvcs=false -ldflags "-X main.Version=%{version}" -o goconserver goconserver.go
go build -trimpath -buildvcs=false -ldflags "-X main.Version=%{version}" -o congo cmd/congo.go
go build -trimpath -buildvcs=false -ldflags "$go_ldflags" -o goconserver goconserver.go
go build -trimpath -buildvcs=false -ldflags "$go_ldflags" -o congo cmd/congo.go
%install
install -Dm0755 goconserver %{buildroot}/usr/bin/goconserver
@@ -243,6 +300,7 @@ mkdir -p %{buildroot}/var/log/goconserver %{buildroot}/var/lib/goconserver
%dir /var/lib/goconserver
%changelog
$native_changelog
* Mon Aug 10 2026 xCAT build - $version-4.el$rel
- Build inside a mock chroot (no host build). Modules are downloaded at build time but pinned +
integrity-checked by a committed go.sum (no `go mod tidy`, no vendored tree). Compiled in the
+2
View File
@@ -0,0 +1,2 @@
234828b7a89e0e303d2556310ee549fbcf253d28de937bac3da13d6294262ac1 go1.25.12.linux-amd64.tar.gz
64adb4ddefef4f0a6f11af550547f39bf510350da69ab308438a21eacfde97ad go1.25.12.linux-ppc64le.tar.gz
+3
View File
@@ -30,6 +30,9 @@ grub2-xcat provides some grub2 resources generated by grub2-mknetdir,including g
and the EL grub2 UEFI image for riscv64 nodes, which boot through UEFI and grub2 only.
%define _binaries_in_noarch_packages_terminate_build 0
%if 0%{?openEuler}
%global __strip /bin/true
%endif
%prep
#cp ./grub2-res.tar.gz /root/rpmbuild/SOURCES/
+291
View File
@@ -0,0 +1,291 @@
package XCAT::NativeInputs;
use strict;
use warnings;
use Cwd qw(abs_path);
use Digest::SHA ();
use Exporter qw(import);
use File::Basename qw(basename);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use JSON::PP;
our @EXPORT_OK = qw(load_inputs stage_inputs verify_input rpm_identity validate_outputs publisher_trust);
sub read_file {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $data = <$fh>;
close $fh or die "Cannot close $path: $!\n";
return $data;
}
sub sha256 {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
binmode $fh;
my $sha = Digest::SHA->new(256)->addfile($fh)->hexdigest;
close $fh or die "Cannot close $path: $!\n";
return $sha;
}
sub capture {
my (@args) = @_;
open my $fh, '-|', @args or die "Cannot execute $args[0]: $!\n";
local $/;
my $out = <$fh> // '';
close $fh or die "Command failed: @args\n";
$out =~ s/\s+\z//;
return $out;
}
sub run {
my (@args) = @_;
system(@args) == 0 or die "Command failed: @args\n";
}
sub pinned_file {
my ($root, $entry) = @_;
die "Invalid pinned path\n" unless ($entry->{path} // '') =~ m{\A[\w./-]+\z}
&& $entry->{path} !~ m{(?:\A|/)\.\.(?:/|\z)|\A/};
die "Missing input $entry->{path}\n" unless -f "$root/$entry->{path}";
my $path = abs_path("$root/$entry->{path}") // die "Missing input $entry->{path}\n";
die "Input escapes repository: $entry->{path}\n" unless index($path, "$root/") == 0;
die "Input SHA256 mismatch: $entry->{path}\n" unless sha256($path) eq ($entry->{sha256} // '');
return $path;
}
sub load_inputs {
my ($root, $required) = @_;
$root = abs_path($root) // die "Missing repository\n";
my $catalog_path = "$root/openeuler/24.03-ppc64le.inputs.json";
my $catalog = JSON::PP->new->decode(read_file($catalog_path));
die "Unsupported native input catalog\n" unless ($catalog->{version} // 0) == 1
&& ($catalog->{target} // '') eq 'openeuler-24.03-ppc64le';
my $key = $catalog->{publisher_key};
die "Invalid publisher fingerprint\n" unless ($key->{fingerprint} // '') =~ /\A[0-9A-F]{40}\z/;
my $key_path = pinned_file($root, $key);
my (%nodes, %outputs);
for my $node (@{$catalog->{inputs}}) {
my $name = $node->{name} // '';
die "Invalid native input name '$name'\n" unless $name =~ /\A[\w+.-]+\z/;
die "Duplicate native input '$name'\n" if $nodes{$name};
my $type = $node->{type} // '';
die "Invalid native input type '$type'\n" unless $type =~ /\A(?:srpm|publisher|owner)\z/;
if ($type eq 'owner') {
die "Unsupported native build owner '$name'\n" unless grep { $_ eq $name }
qw(goconserver grub2-xcat ipmitool-xcat syslinux-xcat xnba-undi xCAT-genesis-base
perl-Crypt-Rijndael perl-Crypt-SSLeay perl-HTTP-Async perl-IO-Stty perl-Net-HTTPS-NB perl-Net-Telnet);
}
if ($type ne 'publisher') {
my $uid = $type eq 'owner' && ($name eq 'xnba-undi' || $name eq 'xCAT-genesis-base') ? 0 : 1000;
die "Invalid native build UID for $name\n" unless ($node->{build_uid} // -1) == $uid;
}
if ($type ne 'owner') {
die "Invalid pinned native URL for $name\n" unless ($node->{url} // '') =~
m{\Ahttps://repo\.openeuler\.org/openEuler-24\.03-LTS(?:-SP3)?/[A-Za-z0-9_./+-]+\.rpm\z};
die "Invalid native SHA256 for $name\n" unless ($node->{sha256} // '') =~ /\A[0-9a-f]{64}\z/;
die "Publisher binary must be exact GA: $name\n" if $type eq 'publisher'
&& $node->{url} !~ m{/openEuler-24\.03-LTS/.*\.noarch\.rpm\z};
}
die "Missing output ownership for $name\n" unless ref($node->{outputs}) eq 'ARRAY' && @{$node->{outputs}};
for my $output (@{$node->{outputs}}) {
die "Invalid native output name\n" unless $output =~ /\A[\w+.-]+\z/;
die "Conflicting output ownership: $output\n" if $outputs{$output};
$outputs{$output} = $name;
}
die "Invalid publisher outputs for $name\n" if $type eq 'publisher'
&& (@{$node->{outputs}} != 1 || $node->{outputs}[0] ne $name);
for my $patch (@{$node->{patches} // []}) {
die "Only source inputs accept patches\n" unless $type eq 'srpm';
$patch->{absolute_path} = pinned_file($root, $patch);
}
for my $define (@{$node->{defines} // []}) {
die "Invalid native spec definition for $name\n" unless $type eq 'srpm'
&& $define =~ /\A(?:llvmjit|external_libpq|runselftest|test) [01]\z/;
}
$nodes{$name} = $node;
}
for my $name (sort keys %nodes) {
my $type = $nodes{$name}{type};
for my $dependency (@{$nodes{$name}{needs} // []}) {
die "Missing native dependency '$dependency'\n" unless $nodes{$dependency};
die "Unsupported native execution edge: $name -> $dependency\n"
if $type eq 'publisher' || $nodes{$dependency}{type} eq 'owner';
}
}
my (%mark, @order);
my $visit;
$visit = sub {
my ($name) = @_;
die "Missing native dependency '$name'\n" unless $nodes{$name};
die "Cyclic native dependency at '$name'\n" if ($mark{$name} // '') eq 'visiting';
return if $mark{$name};
$mark{$name} = 'visiting';
$visit->($_) for @{$nodes{$name}{needs} // []};
$mark{$name} = 'done';
push @order, $name;
};
$visit->($_) for sort keys %nodes;
my %selected;
my $select;
$select = sub {
my ($name) = @_;
die "Missing native dependency '$name'\n" unless $nodes{$name};
return if $selected{$name}++;
$select->($_) for @{$nodes{$name}{needs} // []};
};
for my $output (sort keys %$required) {
my $owner = $outputs{$output} // ($nodes{$output} ? $output : undef);
die "No native output owner for '$output'\n" unless $owner;
$select->($owner);
}
$select->($_) for @{$catalog->{build_inputs} // []};
return {catalog => $catalog, nodes => \%nodes, outputs => \%outputs,
order => [grep { $selected{$_} } @order], selected => \%selected,
publisher_key => $key_path, publisher_fingerprint => $key->{fingerprint},
catalog_sha256 => sha256($catalog_path)};
}
sub rpm_identity {
my ($path) = @_;
my @fields = split /\n/, capture('rpm', '-qp', '--qf',
'%{NAME}\n%{ARCH}\n%{SOURCEPACKAGE}\n%{RELEASE}\n', $path);
die "Invalid RPM header: $path\n" unless @fields == 4;
return {name => $fields[0], arch => $fields[1], source => $fields[2] eq '1', release => $fields[3]};
}
sub read_exact {
my ($fh, $size) = @_;
my $data = '';
while (length($data) < $size) {
my $got = read($fh, $data, $size - length($data), length($data));
die "Truncated RPM payload\n" unless defined($got) && $got > 0;
}
return $data;
}
sub reject_elf_payload {
my ($path) = @_;
open my $fh, '-|', 'rpm2cpio', $path or die "Cannot read RPM payload: $!\n";
binmode $fh;
my $error;
eval {
while (1) {
my $header = read_exact($fh, 110);
die "Invalid RPM cpio header\n" unless $header =~ /\A07070[12][0-9A-Fa-f]{104}\z/;
my @fields = map { hex($_) } $header =~ /\A.{6}(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})\z/s;
my ($size, $namesize) = @fields[6, 11];
die "Invalid RPM cpio filename\n" unless $namesize > 0 && $namesize <= 1048576;
my $name = read_exact($fh, $namesize);
die "Invalid RPM cpio filename terminator\n" unless $name =~ s/\0\z//;
read_exact($fh, (4 - (110 + $namesize) % 4) % 4);
last if $name eq 'TRAILER!!!' && $size == 0;
my $prefix = read_exact($fh, $size < 4 ? $size : 4);
die "ELF payload in publisher noarch RPM: $name\n" if $prefix eq "\x7fELF";
$size -= length($prefix);
while ($size) { my $count = $size < 65536 ? $size : 65536; read_exact($fh, $count); $size -= $count; }
read_exact($fh, (4 - $fields[6] % 4) % 4);
}
my $tail;
while (read($fh, $tail, 65536)) { die "Unexpected data after RPM cpio trailer\n" if $tail =~ /[^\0]/; }
1;
} or $error = $@;
my $closed = close($fh);
die $error if $error;
die "rpm2cpio failed: $path\n" unless $closed;
}
sub verify_input {
my ($plan, $node, $path, $db) = @_;
die "Native input SHA256 mismatch: $path\n" unless sha256($path) eq $node->{sha256};
my $out = capture('rpmkeys', '--dbpath', $db, '--checksig', '--verbose', $path);
die "Publisher signature missing or invalid: $path\n" unless $out =~ /Signature.*: OK/i
&& $out !~ /NOKEY|NOT OK|BAD|UNSIGNED/i;
my $id = rpm_identity($path);
die "Native input NAME mismatch: $path\n" unless $id->{name} eq $node->{name};
if ($node->{type} eq 'publisher') {
die "Publisher input is not a noarch binary: $path\n" if $id->{source} || $id->{arch} ne 'noarch';
die "Publisher input is not exact GA: $path\n" unless $id->{release} =~ /\.oe2403\z/;
reject_elf_payload($path);
} else {
die "Native input is not a source RPM: $path\n" unless $id->{source};
}
die "Native input changed during verification: $path\n" unless sha256($path) eq $node->{sha256};
return $id;
}
sub publisher_trust {
my ($plan, $work) = @_;
make_path("$work/trust", "$work/gnupg");
chmod 0700, "$work/gnupg";
my $listing = capture('gpg', '--homedir', "$work/gnupg", '--batch', '--with-colons', '--show-keys', $plan->{publisher_key});
my @primary;
my $pub;
for my $line (split /\n/, $listing) {
my @fields = split /:/, $line;
$pub = 1 if $fields[0] eq 'pub';
if ($pub && $fields[0] eq 'fpr') { push @primary, $fields[9]; $pub = 0; }
}
die "Publisher public key fingerprint mismatch\n" unless @primary == 1 && $primary[0] eq $plan->{publisher_fingerprint};
run('rpmkeys', '--dbpath', "$work/trust", '--import', $plan->{publisher_key});
return "$work/trust";
}
sub stage_inputs {
my ($plan, $work) = @_;
die "Native input staging already exists: $work\n" if -e $work;
make_path($work);
my $db = publisher_trust($plan, $work);
my @ledger;
for my $name (@{$plan->{order}}) {
my $node = $plan->{nodes}{$name};
next if $node->{type} eq 'owner';
make_path("$work/$name");
for my $patch (@{$node->{patches} // []}) {
make_path("$work/$name/patches");
my $staged = "$work/$name/patches/" . basename($patch->{path});
die "Conflicting staged patch: $staged\n" if -e $staged;
copy($patch->{absolute_path}, $staged) or die "Cannot stage native patch: $!\n";
die "Staged patch SHA256 mismatch: $staged\n" unless sha256($staged) eq $patch->{sha256};
chmod 0444, $staged or die "Cannot protect native patch: $!\n";
$patch->{staged} = $staged;
}
my $dest = "$work/$name/" . basename($node->{url});
run('wget', '--https-only', '--tries=3', '--timeout=60', '-O', "$dest.part", $node->{url});
verify_input($plan, $node, "$dest.part", $db);
rename("$dest.part", $dest) or die "Cannot preserve native input: $!\n";
chmod 0444, $dest or die "Cannot protect native input: $!\n";
$node->{staged} = $dest;
push @ledger, {name => $name, type => $node->{type}, url => $node->{url},
sha256 => $node->{sha256}, path => $dest, publisher => $plan->{publisher_fingerprint},
defines => $node->{defines} // [],
patches => [map { {path => $_->{path}, sha256 => $_->{sha256}, staged => $_->{staged}} } @{$node->{patches} // []}]};
}
open my $fh, '>', "$work/inputs.json" or die "Cannot record native input ledger: $!\n";
print {$fh} JSON::PP->new->canonical->pretty->encode({catalog_sha256 => $plan->{catalog_sha256}, inputs => \@ledger});
close $fh or die "Cannot close native input ledger: $!\n";
$plan->{trust_db} = $db;
}
sub validate_outputs {
my ($node, $paths, $require_all) = @_;
my %allowed = map { $_ => 1 } @{$node->{outputs}};
my %seen;
for my $path (@$paths) {
my $id = rpm_identity($path);
next if $id->{source};
die "Unexpected output from $node->{name}: $id->{name}\n" unless $allowed{$id->{name}};
die "Duplicate output from $node->{name}: $id->{name}\n" if $seen{$id->{name}}++;
die "Foreign output architecture: $id->{arch}\n" unless $id->{arch} eq 'ppc64le' || $id->{arch} eq 'noarch';
}
if ($require_all) {
die "Missing output from $node->{name}: $_\n" for grep { !$seen{$_} } sort keys %allowed;
}
return \%seen;
}
1;
@@ -0,0 +1,7 @@
include('templates/openeuler-20.03-sp4.tpl')
config_opts['root'] = 'openeuler-20.03sp4-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['openeuler_repository_release'] = '20.03-LTS-SP4'
config_opts['openeuler_repositories'] = ('OS', 'everything', 'update')
include('templates/openeuler-lts-xcat.tpl')
@@ -0,0 +1,7 @@
include('templates/openeuler-22.03-sp4.tpl')
config_opts['root'] = 'openeuler-22.03sp4-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['openeuler_repository_release'] = '22.03-LTS-SP4'
config_opts['openeuler_repositories'] = ('OS', 'everything', 'update')
include('templates/openeuler-lts-xcat.tpl')
+15
View File
@@ -0,0 +1,15 @@
config_opts['root'] = 'openeuler-24.03-ppc64le'
config_opts['target_arch'] = 'ppc64le'
config_opts['legal_host_arches'] = ('ppc64le',)
config_opts['releasever'] = '24.03LTS'
config_opts['package_manager'] = 'dnf'
config_opts['isolation'] = 'simple'
config_opts['chrootuid'] = 1000
config_opts['chrootgid'] = 1000
config_opts['useradd'] = '/usr/sbin/useradd -o -m -u {{chrootuid}} -g {{chrootgid}} -d {{chroothome}} -N {{chrootuser}}'
config_opts['use_bootstrap'] = False
config_opts['use_bootstrap_container'] = False
config_opts['chroot_setup_cmd'] = 'install openEuler-rpm-config openEuler-release shadow rpm-build dnf-plugins-core gcc make perl-interpreter'
config_opts['openeuler_repository_release'] = '24.03-LTS'
config_opts['openeuler_repositories'] = ('OS',)
include('templates/openeuler-lts-xcat.tpl')
@@ -0,0 +1,8 @@
include('templates/openeuler-24.03.tpl')
config_opts['root'] = 'openeuler-24.03sp1-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['releasever'] = '24.03LTS_SP1'
config_opts['openeuler_repository_release'] = '24.03-LTS-SP1'
config_opts['openeuler_repositories'] = ('OS', 'everything', 'update')
include('templates/openeuler-lts-xcat.tpl')
@@ -0,0 +1,8 @@
include('templates/openeuler-24.03.tpl')
config_opts['root'] = 'openeuler-24.03sp3-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['releasever'] = '24.03LTS_SP3'
config_opts['openeuler_repository_release'] = '24.03-LTS-SP3'
config_opts['openeuler_repositories'] = ('OS', 'everything', 'update')
include('templates/openeuler-lts-xcat.tpl')
@@ -0,0 +1,8 @@
include('templates/openeuler-24.03.tpl')
config_opts['root'] = 'openeuler-24.03sp4-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['releasever'] = '24.03LTS_SP4'
config_opts['openeuler_repository_release'] = '24.03-LTS-SP4'
config_opts['openeuler_repositories'] = ('OS', 'everything', 'update')
include('templates/openeuler-lts-xcat.tpl')
@@ -0,0 +1,31 @@
config_opts['dist'] = ''
config_opts['use_bootstrap_image'] = False
config_opts['description'] = 'openEuler ' + config_opts['openeuler_repository_release']
config_opts['dnf.conf'] = """
[main]
keepcache=1
reposdir=/dev/null
logfile=/var/log/dnf.log
retries=20
obsoletes=1
gpgcheck=1
assumeyes=1
metadata_expire=0
best=1
install_weak_deps=0
skip_if_unavailable=0
protected_packages=
"""
_openeuler_root = 'https://repo.openeuler.org/openEuler-' + config_opts['openeuler_repository_release']
_openeuler_arch = config_opts['target_arch']
for _openeuler_repo in config_opts['openeuler_repositories']:
config_opts['dnf.conf'] += """
[{repo}]
name=openEuler {release} {repo}
baseurl={root}/{repo}/{arch}/
enabled=1
gpgcheck=1
gpgkey={root}/OS/{arch}/RPM-GPG-KEY-openEuler
skip_if_unavailable=0
""".format(repo=_openeuler_repo, release=config_opts['openeuler_repository_release'],
root=_openeuler_root, arch=_openeuler_arch)
+325 -30
View File
@@ -13,6 +13,7 @@ use File::Temp qw(tempdir tempfile);
use Getopt::Long qw(GetOptions);
use Parallel::ForkManager;
use POSIX qw(strftime);
use JSON::PP;
use FindBin qw($RealBin);
use lib $RealBin, "$RealBin/lib";
use MockBuildUtils qw(sh_quote print_step version_matches required_pkgs
@@ -20,11 +21,13 @@ use MockBuildUtils qw(sh_quote print_step version_matches required_pkgs
read_manifest verify_repo_packages verify_repo_signature verify_rpm_signatures
rpm_version rpm_release rpm_sigmd5 restamp_release_line
cross_copy_genesis finalize_xcat_dep bump_dep_release_suffix
build_mock_uniqueext rpmkeys_checksig_problem);
build_mock_uniqueext rpmkeys_checksig_problem
openeuler_build_target openeuler_repo_subdir);
# print_step and sh_quote come from MockBuildUtils above; XCAT::BuildUtils carries the same
# print_step, so it is deliberately NOT imported here (one definition, no redefinition warning).
use XCAT::BuildUtils qw(
capture_command
digest_file
every_step_failed
hashes_equal
read_lines
@@ -36,6 +39,7 @@ use XCAT::GenesisRelease qw(
validated_release_checksums
verify_release_file
);
use XCAT::NativeInputs qw(load_inputs stage_inputs verify_input rpm_identity validate_outputs publisher_trust);
# --- Mount-namespace isolation: guard the host cgroup against mock teardown propagation ----------
# mock mounts /sys/fs/cgroup into every build chroot. On these systemd build hosts every mount is
@@ -133,6 +137,7 @@ my $no_verify_repo = 0;
my @HELD_LOCKS;
my $LOCK_OWNER_PID;
my ($COMMON_STAGE, $COMMON_DESTINATION, $COMMON_BACKUP);
my %NATIVE_PLANS;
for my $sig (qw(INT TERM HUP)) {
$SIG{$sig} = sub { exit 1; };
}
@@ -347,6 +352,9 @@ if ($install_deps) {
die "FATAL: still missing after install: " . join(', ', @missing) . "\n" if @missing;
print " perl modules present: " . join(', ', @modules) . "\n";
print " host is ready\n";
if (lc($os_id) eq 'openeuler') {
install_mock_cfg(basename($_, '.cfg')) for glob("$repo_root/mock-configs/openeuler-*.cfg");
}
exit 0;
}
@@ -381,8 +389,10 @@ if ($genesis_release ne '') {
# ONLY the host arch (uname -m) -- the other arch is produced on its own build host --
# except for the forcearch targets (%forcearch_targets, --target only), which are
# cross-built here through qemu-user-static.
my $native_target = openeuler_build_target(\%os, $host_arch);
my @build_targets = $target
? ($target)
: defined($native_target) ? ($native_target)
: map { resolve_mock_cfg($os_id, $_, $host_arch) } (8, 9, 10);
# What a target builds. The mock-core-configs targets (<os>+epel-<rel>-<arch>) build every
@@ -473,6 +483,14 @@ sub build_one_target {
my %req = %{ $MANIFEST{$target} // {} };
die "FATAL: no manifest section for target '$target' in packages-manifest.conf\n"
if !%req;
my $native = $target eq 'openeuler-24.03-ppc64le' ? load_inputs($repo_root, \%req) : undef;
$NATIVE_PLANS{$target} = $native if $native;
if ($native) {
die "Native POWER collection requires signing and verification\n"
if !$gpg_sign || $no_verify_repo;
die "Native POWER inputs require a complete owner run\n"
if $skip_build || $skip_xcat_dep || $skip_perl || @extra_collect_dirs;
}
my $run_root = "$output_root/$run_id";
my $build_root = "$run_root/build-results";
@@ -505,6 +523,8 @@ my @dep_builders = (
{ name => 'goconserver', script => "$repo_root/goconserver/mockbuild.pl" },
{ name => 'conserver-xcat', script => "$repo_root/conserver/mockbuild.pl" },
{ name => 'xnba-undi', script => "$repo_root/xnba/mockbuild.pl", noarch => 1 },
{ name => 'python3-scp', srpm => "$repo_root/python-scp/python-scp-0.14.5-1.oe2403.src.rpm",
sha256 => '3461d2a3fe0122cac2893d8465ad1271ae21e5570a31d4402e3f887ef545a0e8' },
);
my %profile_builds = map { $_ => 1 } @{ $profile->{dep_builders} };
@@ -518,11 +538,16 @@ die "Missing xCAT build script: $xcat_src/buildrpms.pl\n"
my @active_dep_builders;
for my $b (@dep_builders) {
next if !$profile_builds{$b->{name}};
if ($b->{srpm}) {
push @active_dep_builders, $b if $req{$b->{name}};
next;
}
if (-f $b->{script}) {
push @active_dep_builders, $b;
next;
}
print "WARN: missing dep builder script, skipping: $b->{script}\n";
die "Missing native owner script: $b->{script}\n" if $native && $req{$b->{name}};
}
die "Missing perl builder script: $perl_builder\n"
if !$skip_perl && !$perl_builder;
@@ -576,9 +601,35 @@ print "srpm_repo_dir: $srpm_repo_dir\n";
print "srpm_tarball: $srpm_tarball\n";
my @collect_roots;
my @native_source_roots;
if ($native && !$dry_run) {
stage_inputs($native, "$run_root/native-inputs");
}
if (!$skip_build && !$skip_xcat_dep) {
for my $builder (grep { $_->{srpm} } @active_dep_builders) {
my $source = $builder->{srpm};
die "Missing source RPM: $source\n" unless -f $source;
die "Source RPM SHA256 mismatch: $source\n" unless digest_file($source) eq $builder->{sha256};
next if $dry_run;
my $stage_dir = "$run_root/source-rpms/$builder->{name}";
make_path($stage_dir);
my $staged = "$stage_dir/" . basename($source);
copy($source, $staged) or die "Cannot stage source RPM $source: $!\n";
die "Staged source RPM SHA256 mismatch: $staged\n" unless digest_file($staged) eq $builder->{sha256};
$builder->{srpm} = $staged;
}
}
install_mock_cfg($target);
if ($native) {
my ($runtime, $sources) = build_native_inputs($native, $target, \%req, $run_root, $log_root);
push @collect_roots, $runtime;
push @native_source_roots, @$sources;
}
if ($scrub_all_chroots) {
run_step(
step => "Scrub all chroots for target $target",
@@ -604,7 +655,10 @@ if (!$skip_build) {
my $step_result = "$build_root/$name";
my $step_log = "$log_root/$name";
my $step_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, $name);
my $cmd = join(' ',
my $cmd = $builder->{srpm}
? source_rpm_build_command($builder, $target, $step_uniqueext, $step_result, $step_log,
"$run_root/source-rpms/$name")
: join(' ',
'perl', shell_quote($script),
'--mock-cfg', shell_quote($builder->{noarch} ? $profile->{noarch_cfg} : $target),
($profile->{forcearch} && !$builder->{noarch} ? ('--target-arch', shell_quote($arch)) : ()),
@@ -614,13 +668,10 @@ if (!$skip_build) {
# host-local, run-scoped work dir so /tmp doesn't collide between runs
'--work-dir', shell_quote("/tmp/mockbuild-all-$run_id/$name"),
'--build-timestamp', $SOURCE_DATE_EPOCH,
# goconserver generates its spec at build time (from an upstream clone), so the
# in-tree spec Release bump above cannot reach it. Hand the CD suffix down so its
# NVR advances per run too, and pin the clone to an immutable commit (not the moving
# 'master') so the build is reproducible.
($name eq 'goconserver'
? ('--go-ref', sh_quote($GOCONSERVER_REF),
($RELEASE_BUMP ne '' ? ('--release-suffix', sh_quote($RELEASE_BUMP)) : ()))
($name eq 'goconserver' ? ('--go-ref', sh_quote($GOCONSERVER_REF)) : ()),
# Generated specs need the same release suffix as in-tree specs.
(($name eq 'goconserver' || $name eq 'xnba-undi') && $RELEASE_BUMP ne ''
? ('--release-suffix', sh_quote($RELEASE_BUMP))
: ()),
);
push @build_steps, {
@@ -630,12 +681,13 @@ if (!$skip_build) {
log => "$log_root/$name/run.log",
scrub_cfg => $target,
scrub_uniqueext => $step_uniqueext,
($native ? (native_results => {$name => $step_result}) : ()),
};
push @collect_roots, $step_result;
}
}
my @perl_pkgs = sort grep { /^perl-/ } keys %req; # manifest: perl packages required here
my @perl_pkgs = sort grep { /^perl-/ && (!$native || $native->{nodes}{$_}{type} eq 'owner') } keys %req;
if (!$skip_perl && @perl_pkgs) {
my $perl_result = "$build_root/perl/$arch";
my $perl_log = "$log_root/perl/$arch";
@@ -668,6 +720,7 @@ if (!$skip_build) {
step => 'Build perl xcat-dep packages',
cmd => $cmd,
log => "$log_root/perl-build.log",
($native ? (native_results => {map { $_ => "$perl_result/$_" } @perl_pkgs}) : ()),
};
push @collect_roots, $perl_result;
}
@@ -711,6 +764,7 @@ if (!$skip_build) {
'--verbose',
'--xcat_dep_path', shell_quote($repo_root),
);
$cmd = native_owner_command($native, $target, $cmd, 0) if $native;
push @build_steps, {
id => 'genesis',
step => 'Build xCAT-genesis-base (per-target, OS-dependent)',
@@ -718,10 +772,16 @@ if (!$skip_build) {
cwd => $xcat_src,
log => "$log_root/genesis-build.log",
scrub_cfg => "xCAT-genesis-base-$target",
($native ? (native_results => {'xCAT-genesis-base' => "$xcat_src/dist/$target/rpms"}) : ()),
};
}
if (@build_steps) {
if ($native) {
for my $step (grep { $_->{id} ne 'genesis' } @build_steps) {
$step->{cmd} = native_owner_command($native, $target, $step->{cmd}, 1000);
}
}
# Prefer the caller-supplied cap (global budget / active targets). Fall back to the old
# behaviour (all steps at once) only when unset.
my $effective_parallel_builds =
@@ -767,6 +827,20 @@ if (!$skip_build) {
# -- ignore a genesis failure when a matching rpm already exists in dist/ -- is gone; a
# stale artifact from a previous build must never mask a failed genesis build.)
die "FATAL: required build step(s) failed for $target: @failed\n" if @failed;
if ($native && !$dry_run) {
for my $step (@build_steps) {
for my $name (sort keys %{$step->{native_results} // {}}) {
my $directory = $step->{native_results}{$name};
die "Missing native owner result: $directory\n" unless -d $directory;
my @rpms;
find({no_chdir => 1, wanted => sub {
push @rpms, $File::Find::name if -f $_ && /\.rpm\z/ && !/\.src\.rpm\z/
&& ($name ne 'xCAT-genesis-base' || basename($_) =~ /^xCAT-genesis-base-/);
}}, $directory);
validate_outputs($native->{nodes}{$name}, \@rpms, 1);
}
}
}
}
}
@@ -787,6 +861,7 @@ if ($skip_build) {
push @collect_roots, @extra_collect_dirs;
@collect_roots = uniq(@collect_roots);
my @srpm_collect_roots = uniq(@collect_roots);
push @srpm_collect_roots, @native_source_roots;
if ($genesis_release && !$dry_run) {
remove_genesis_packages($repo_dir, 0);
@@ -835,6 +910,7 @@ if (!$dry_run && $RELEASE_BUMP ne '') {
my @rmiss;
for my $pkg (required_pkgs([sort keys %req], $skip_genesis, $skip_perl, $skip_xcat_dep)) {
next if $pkg eq 'xCAT-genesis-base';
next if $native && $native->{nodes}{$pkg} && $native->{nodes}{$pkg}{type} eq 'publisher';
my $rel = rpm_release($repo_dir, $pkg);
next if !defined $rel; # a missing rpm is caught by the completeness gate in deploy_target
push @rmiss, "$pkg: Release '$rel' is missing the CD bump '$RELEASE_BUMP'"
@@ -940,6 +1016,21 @@ print "SRPM Tarball: $srpm_tarball\n" if !$skip_tarball;
# which dep builders run and which rpms the deployed repo must contain.
sub target_profile {
my ($target) = @_;
if (my $native = openeuler_repo_subdir($target)) {
my ($version, $arch) = $target =~ /\Aopeneuler-(.*)-([^-]+)\z/;
die "Native target '$target' requires a $arch build host, found $host_arch\n"
unless $arch eq $host_arch;
return {
rel => $version,
arch => $arch,
noarch_cfg => $target,
forcearch => 0,
epel => 0,
dep_builders => [qw(grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi python3-scp)],
required => [qw(ipmitool-xcat syslinux-xcat grub2-xcat xnba-undi
perl-IO-Stty perl-HTTP-Async perl-Net-HTTPS-NB)],
};
}
if (my $fa = $forcearch_targets{$target}) {
return {
%{$fa},
@@ -969,9 +1060,11 @@ sub target_profile {
# overwrite one the host already has.
sub install_mock_cfg {
my ($cfg) = @_;
my $src = "$repo_root/mock-configs/$cfg.cfg";
install_mock_cfg('templates/openeuler-lts-xcat') if $cfg =~ /^openeuler-/;
my $extension = $cfg =~ m{^templates/} ? 'tpl' : 'cfg';
my $src = "$repo_root/mock-configs/$cfg.$extension";
return if !-f $src;
my $dst = "/etc/mock/$cfg.cfg";
my $dst = "/etc/mock/$cfg.$extension";
if (-f $dst) {
die "$dst differs from $src: the build would not use the configuration shipped in this"
. " tree. Remove or update the host copy (it is never overwritten here) and rerun.\n"
@@ -984,6 +1077,145 @@ sub install_mock_cfg {
chmod 0644, $dst;
}
sub source_rpm_build_command {
my ($builder, $target, $uniqueext, $result, $log, $work) = @_;
my $cfg = "$work/mock-deterministic.cfg";
if (!$dry_run) {
make_path($work, $result);
open my $fh, '>', $cfg or die "Cannot write $cfg: $!\n";
print {$fh} "include('/etc/mock/$target.cfg')\n";
print {$fh} "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$SOURCE_DATE_EPOCH'\n";
close $fh or die "Cannot close $cfg: $!\n";
}
my $mock = join(' ', 'mock', '-r', sh_quote($cfg), '--uniqueext', sh_quote($uniqueext),
'--define', sh_quote('use_source_date_epoch_as_buildtime 1'),
'--define', sh_quote('clamp_mtime_to_source_date_epoch 1'),
'--define', sh_quote('_buildhost xcat-build'));
$mock .= join('', map { ' --define ' . sh_quote($_) } @{$builder->{defines} // []});
my $srpm = sh_quote($builder->{srpm});
my $prefix = '';
if ($RELEASE_BUMP ne '' || @{$builder->{patches} // []} || @{$builder->{defines} // []}) {
my $top = "$work/restamp";
if (!$dry_run) {
make_path(map { "$top/$_" } qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS));
}
run_step(step => "Unpack source RPM: $builder->{name}",
cmd => 'rpm -i --define ' . sh_quote("_topdir $top") . " $srpm",
log => "$log/srpm-unpack.log");
my @specs = $dry_run ? ("$top/SPECS/*.spec") : bsd_glob("$top/SPECS/*.spec");
die "Expected one spec in source RPM: $builder->{srpm}\n" unless @specs == 1;
bump_dep_release_suffix($top, $RELEASE_BUMP) if !$dry_run && $RELEASE_BUMP ne '';
for my $patch (@{$builder->{patches} // []}) {
my $path = $patch->{staged} // $patch->{absolute_path};
die "Source patch SHA256 mismatch: $path\n" unless digest_file($path) eq $patch->{sha256};
run_step(step => "Apply native source patch: $builder->{name}",
cmd => 'patch --batch --fuzz=0 -p1 -d ' . sh_quote("$top/SPECS")
. ' -i ' . sh_quote($path), log => "$log/spec-patch.log");
}
my $restamped = "$work/restamp-srpm";
make_path($restamped) unless $dry_run;
$prefix = "$mock --buildsrpm --spec " . sh_quote($specs[0])
. ' --sources ' . sh_quote("$top/SOURCES") . ' --resultdir ' . sh_quote($restamped)
. ' && set -- ' . sh_quote($restamped) . '/*.src.rpm'
. ' && test "$#" -eq 1 && test -f "$1" && ';
$srpm = '"$1"';
}
return $prefix . "$mock --rebuild $srpm --resultdir " . sh_quote($result);
}
sub native_owner_command {
my ($plan, $target, $command, $uid) = @_;
my $overlay = $plan->{overlays}{$uid} // die "Missing native mock overlay\n";
my $script = 'mount --bind ' . sh_quote($overlay) . ' ' . sh_quote("/etc/mock/$target.cfg")
. ' && exec sh -c ' . sh_quote($command);
return 'unshare --mount --propagation private -- sh -c ' . sh_quote($script);
}
sub native_overlay {
my ($plan, $target, $work, $prereqs) = @_;
$plan->{overlays} = {1000 => "$work/native-1000.cfg", 0 => "$work/native-genesis-0.cfg",
procenv => "$work/native-procenv-bootstrap.cfg"};
return if $dry_run;
my $base = "$work/native-base.cfg";
copy("/etc/mock/$target.cfg", $base) or die "Cannot snapshot native mock configuration: $!\n";
my $url = $prereqs;
$url =~ s{([^A-Za-z0-9_./~-])}{sprintf('%%%02X', ord($1))}ge;
my $repo = "\n[xcat-native-inputs]\nname=xCAT native build prerequisites\nbaseurl=file://$url\n"
. "gpgkey=file://$url/repodata/repomd.xml.key\ngpgcheck=1\nrepo_gpgcheck=1\n"
. "enabled=1\nskip_if_unavailable=0\n";
for my $key (1000, 0, 'procenv') {
my $uid = $key eq 'procenv' ? 1000 : $key;
open my $fh, '>', $plan->{overlays}{$key} or die "Cannot write native overlay: $!\n";
print {$fh} 'include(' . JSON::PP->new->encode($base) . ")\n";
print {$fh} "config_opts['chrootuid'] = $uid\nconfig_opts['chrootgid'] = 1000\n";
print {$fh} "config_opts['dnf.conf'] += \"\"\"$repo\"\"\"\n";
print {$fh} "config_opts['plugin_conf']['bind_mount_enable'] = True\n";
print {$fh} "config_opts['plugin_conf']['procenv_enable'] = " . ($key eq 'procenv' ? 'False' : 'True') . "\n";
print {$fh} "config_opts['plugin_conf']['bind_mount_opts']['dirs'].append("
. '(' . JSON::PP->new->encode($prereqs) . ', ' . JSON::PP->new->encode($prereqs) . "))\n";
close $fh or die "Cannot close native overlay: $!\n";
}
open my $ledger, '>', "$work/native-overlays.json" or die "Cannot record native overlays: $!\n";
print {$ledger} JSON::PP->new->canonical->pretty->encode({base => {path => $base, sha256 => digest_file($base)},
overlays => [map { {purpose => $_, path => $plan->{overlays}{$_}, sha256 => digest_file($plan->{overlays}{$_})} } (1000, 0, 'procenv')]});
close $ledger or die "Cannot close native overlay ledger: $!\n";
}
sub build_native_inputs {
my ($plan, $target, $req, $work, $logs) = @_;
my $prereqs = "$work/native-prerequisites";
my $runtime = "$work/native-runtime";
my @source_roots;
make_path($prereqs, $runtime) unless $dry_run;
for my $name (@{$plan->{order}}) {
my $node = $plan->{nodes}{$name};
next unless $node->{type} eq 'publisher';
next if $dry_run;
verify_input($plan, $node, $node->{staged}, $plan->{trust_db});
copy($node->{staged}, "$prereqs/" . basename($node->{staged})) or die "Cannot stage publisher RPM: $!\n";
if ($req->{$name}) {
copy($node->{staged}, "$runtime/" . basename($node->{staged})) or die "Cannot collect publisher RPM: $!\n";
}
}
sign_and_index_repo($prereqs, $plan) unless $dry_run;
native_overlay($plan, $target, $work, $prereqs);
my $sequence = 0;
for my $name (@{$plan->{order}}) {
my $node = $plan->{nodes}{$name};
next unless $node->{type} eq 'srpm';
my $result = "$work/native-results/$name";
my $log = "$logs/native/$name";
my $uniqueext = build_mock_uniqueext("$target-$run_id", ++$sequence, $name);
my %builder = (%$node, srpm => $node->{staged} // "$work/native-inputs/$name/" . basename($node->{url}));
my $command = source_rpm_build_command(\%builder, $target, $uniqueext, $result, $log,
"$work/native-source/$name");
run_step(step => "Build native prerequisite: $name", log => "$log/run.log",
cmd => native_owner_command($plan, $target, $command, $name eq 'procenv' ? 'procenv' : 1000));
next if $dry_run;
my @rpms = grep { !/\.src\.rpm$/ } bsd_glob("$result/*.rpm");
validate_outputs($node, \@rpms, 1);
for my $rpm (@rpms) {
my $base = basename($rpm);
die "Conflicting native prerequisite artifact: $base\n" if -e "$prereqs/$base";
copy($rpm, "$prereqs/$base") or die "Cannot stage native prerequisite: $!\n";
my $id = rpm_identity($rpm);
copy($rpm, "$runtime/$base") or die "Cannot collect native output: $!\n" if $req->{$id->{name}};
}
sign_and_index_repo($prereqs, $plan);
my @problems = verify_rpms_checksig($prereqs, $gpg_key_name, $gpg_home, $plan);
die "Native prerequisite signature failure: @problems\n" if @problems;
open my $ledger, '>>', "$work/native-results.jsonl" or die "Cannot record native result: $!\n";
print {$ledger} JSON::PP->new->canonical->encode({name => $name, source_sha256 => $node->{sha256},
defines => $node->{defines} // [], patches => [map { {path => $_->{path}, sha256 => $_->{sha256}} } @{$node->{patches} // []}],
outputs => [map { {name => rpm_identity($_)->{name}, unsigned_path => $_,
unsigned_sha256 => digest_file($_), signed_sha256 => digest_file("$prereqs/" . basename($_))} } @rpms]}) . "\n";
close $ledger or die "Cannot close native result ledger: $!\n";
push @source_roots, $result;
scrub_buildroot($target, $uniqueext, "$log/scrub.log") unless $keep_buildroots;
}
return ($runtime, \@source_roots);
}
# Assemble the built per-target repo into the deployable, signed per-EL layout
# <repo-dep>/rh<rel>/<arch>: copy the binary rpms, sign, createrepo, and drop the
# xcat-dep.repo / mklocalrepo.sh / buildinfo.txt (ready to push to xcat.org).
@@ -992,7 +1224,8 @@ sub deploy_target {
my $rel = $info->{rel};
my $src = $info->{repo_dir};
my $tarch = $info->{profile}{arch};
my $dest = "$repo_dep/rh$rel/$tarch";
my $subdir = openeuler_repo_subdir($tgt) // "rh$rel/$tarch";
my $dest = "$repo_dep/$subdir";
print_step("Deploy $tgt -> $dest");
return if $dry_run;
@@ -1020,8 +1253,8 @@ sub deploy_target {
# rpm an earlier layout left in the collection. On the STAGE, so the published cell is
# already correct when it is swapped in.
remove_genesis_packages($stage, 0) if $genesis_release;
sign_and_index_repo($stage);
write_dep_repo_metadata($stage, $rel, $tarch);
sign_and_index_repo($stage, $NATIVE_PLANS{$tgt});
write_dep_repo_metadata($stage, $rel, $tarch, $subdir);
# Automatic completeness + signature gate on the freshly signed cell -- the single
# consolidated gate (verify_target_repo, the same one --verify-repo runs). Asserts every
# manifest-required package is present at its pinned version, the repomd signature verifies,
@@ -1051,7 +1284,7 @@ sub deploy_target {
remove_tree($old) if -d $old;
my $n = scalar(grep { !/\.src\.rpm$/ } bsd_glob("$dest/*.rpm"));
print "Deployed rh$rel/$tarch: $n rpms\n";
print "Deployed $subdir: $n rpms\n";
}
sub publish_genesis_common_repo {
@@ -1176,8 +1409,22 @@ sub createrepo_c_cmd {
}
sub sign_and_index_repo {
my ($dir) = @_;
my ($dir, $native) = @_;
my @rpms = grep { !/\.src\.rpm$/ } bsd_glob("$dir/*.rpm");
if ($native) {
my @built;
for my $rpm (@rpms) {
my $id = rpm_identity($rpm);
my $owner = $native->{outputs}{$id->{name}} // die "Undeclared native output: $id->{name}\n";
my $node = $native->{nodes}{$owner};
if ($node->{type} eq 'publisher') {
die "Publisher input changed before signing: $rpm\n" unless digest_file($rpm) eq $node->{sha256};
} else {
push @built, $rpm;
}
}
@rpms = @built;
}
if ($gpg_sign && @rpms) {
local $ENV{GNUPGHOME} = $gpg_home if $gpg_home;
run_simple('rpmsign --define ' . shell_quote("%_gpg_name $gpg_key_name")
@@ -1191,21 +1438,26 @@ sub sign_and_index_repo {
unlink "$repomd.asc" if -f "$repomd.asc";
run_simple("gpg -a --detach-sign --default-key " . sh_quote($gpg_key_name) . ' ' . sh_quote($repomd));
run_simple("gpg -a --export " . sh_quote($gpg_key_name) . " > " . sh_quote("$repomd.key"));
if ($native) {
run_simple('cat ' . sh_quote($native->{publisher_key}) . ' >> ' . sh_quote("$repomd.key"));
}
}
}
sub write_dep_repo_metadata {
my ($dir, $rel, $tarch) = @_;
my $baseurl = "https://xcat.org/files/xcat/repos/yum/devel/xcat-dep/rh$rel/$tarch";
my $gpgcheck = $gpg_sign ? 1 : 0;
my $gpgkey_line = $gpg_sign ? "gpgkey=$baseurl/repodata/repomd.xml.key" : "# gpgkey=";
my ($dir, $rel, $tarch, $subdir) = @_;
$subdir //= "rh$rel/$tarch";
my $baseurl = "https://xcat.org/files/xcat/repos/yum/devel/xcat-dep/$subdir";
my $gpgcheck = $gpg_sign || $subdir =~ /^openeuler/ ? 1 : 0;
my $gpgkey_line = $gpgcheck ? "gpgkey=$baseurl/repodata/repomd.xml.key" : "# gpgkey=";
my $label = $subdir =~ /^openeuler/ ? $subdir : "rh$rel $tarch";
# repo_gpgcheck=1 makes clients verify the DETACHED repomd.xml signature (repomd.xml.asc) against
# gpgkey before trusting the metadata -- sign_and_index_repo produces both, so enforce it. Mirrors
# gpgcheck: off when the repo is unsigned.
open my $r, '>', "$dir/xcat-dep.repo" or die "Cannot write $dir/xcat-dep.repo: $!\n";
print {$r} <<"EOF";
[xcat-dep]
name=xCAT 2 dependencies (rh$rel $tarch)
name=xCAT 2 dependencies ($label)
baseurl=$baseurl
enabled=1
gpgcheck=$gpgcheck
@@ -1215,7 +1467,7 @@ EOF
close $r;
write_local_repo_helper($dir);
write_buildinfo($dir, "rh$rel/$tarch");
write_buildinfo($dir, $subdir);
}
sub write_common_repo_metadata {
@@ -1273,6 +1525,10 @@ sub write_buildinfo {
my $build_time = strftime("%a %b %e %H:%M:%S %Z %Y", gmtime($SOURCE_DATE_EPOCH));
my $build_machine = `hostname`; chomp $build_machine;
my $commit = `git -C "$repo_root" rev-parse HEAD 2>/dev/null`; chomp $commit;
if (!$commit && -f "$repo_root/Gitinfo") {
($commit) = read_lines("$repo_root/Gitinfo");
$commit =~ s/\s+\z// if defined($commit);
}
$commit ||= 'unknown';
my $commit_short = substr($commit, 0, 7);
my $release = strftime('snap%Y%m%d%H%M', gmtime($SOURCE_DATE_EPOCH));
@@ -1339,7 +1595,9 @@ Options:
the target is present at a version satisfying its pin AND that the repomd
is signed by --gpg-key-name; exits 0 if complete, or lists each MISSING/
VERSION/UNSIGNED/WRONGKEY problem and fails. The target is derived from the path
(.../rh<N>/<arch> -> alma+epel-<N>-<arch>) unless --target is given; the
(.../rh<N>/<arch> -> alma+epel-<N>-<arch>, or
.../openeuler<releaseSP>/<arch> -> openeuler-<releaseSP>-<arch>)
unless --target is given; the
manifest and gpg key/home come from the usual options. Use alone.
--no-verify-repo Suppress the AUTOMATIC post-build completeness+signature gate that runs
after each target's repo is finalized (default: verification ON)
@@ -1349,7 +1607,12 @@ Options:
--target NAME Build only this target (<ID>+epel-<REL>-<ARCH>, or a forcearch
config from mock-configs/ such as rocky-10-riscv64-xcat, which
cross-builds that arch on this host); default is the host arch
across rh8, rh9 and rh10
across rh8, rh9 and rh10. On openEuler the default retains the exact
host release and service pack, e.g. openeuler-24.03sp3-x86_64.
Native targets require the matching host architecture and deploy to
<repo-dep>/openeuler<releaseSP>/<arch> with signature checks enabled.
The build host must provide mock and its Perl dependencies; openEuler
24.03 LTS-SP3 can build older releases in their exact native targets.
--nproc N Parallel jobs for buildrpms.pl (default: 1)
--parallel-builds N Max concurrent top-level build steps within one EL target (default: auto)
--parallel-targets N Concurrent EL targets (rh8/rh9/rh10). 0/auto = all at once, 1 = serial,
@@ -1669,7 +1932,7 @@ sub rpm_vercmp_segment {
# check: it verifies each rpm's header/payload digests AND that the signature is by this key (NOKEY /
# NOT OK => a real failure, since the key IS imported). Returns @problems.
sub verify_rpms_checksig {
my ($dir, $keyname, $home) = @_;
my ($dir, $keyname, $home, $native) = @_;
my @rpms = grep { !/\.src\.rpm$/ } glob("$dir/*.rpm");
return () unless @rpms;
require_command('rpmkeys');
@@ -1682,9 +1945,27 @@ sub verify_rpms_checksig {
my $dbopt = '--dbpath ' . sh_quote($tmpdb);
system("rpmkeys $dbopt --import " . sh_quote($keyfile) . ' >/dev/null 2>&1') == 0
or return ("SIGKEY: rpmkeys --import of '$keyname' into the temp keyring failed");
my $publisher_db;
if ($native) {
my $trust = tempdir('native-publisher-XXXXXXXX', TMPDIR => 1, CLEANUP => 1);
my $ok = eval { $publisher_db = publisher_trust($native, $trust); 1; };
return ("SIGKEY: $@") unless $ok;
}
my @problems;
for my $rpm (@rpms) {
my $out = `rpmkeys $dbopt --checksig -v ${\ sh_quote($rpm)} 2>&1`;
my $rpm_dbopt = $dbopt;
if ($native) {
my $id = rpm_identity($rpm);
my $owner = $native->{outputs}{$id->{name}};
if (!$owner) { push @problems, "Undeclared native output: $id->{name}"; next; }
my $node = $native->{nodes}{$owner};
if ($node->{type} eq 'publisher') {
my $ok = eval { verify_input($native, $node, $rpm, $publisher_db); 1; };
push @problems, $@ unless $ok;
next;
}
}
my $out = `rpmkeys $rpm_dbopt --checksig -v ${\ sh_quote($rpm)} 2>&1`;
push @problems, rpmkeys_checksig_problem(basename($rpm), $? >> 8, $out);
}
return @problems;
@@ -1725,6 +2006,7 @@ sub verify_target_repo {
my %MAN = read_manifest($manifest);
my %req = %{ $MAN{$tgt} // {} };
die "FATAL: no manifest section for target '$tgt' in $manifest\n" if !%req;
my $native;
# The WHOLE manifest, deliberately -- the --skip-* flags are NOT applied here. They say what
# this INVOCATION built; they never say what the verified repository may be missing. Honouring
# them let a repo with no xCAT-genesis-base pass whenever the verifying run happened to carry
@@ -1738,6 +2020,10 @@ sub verify_target_repo {
my %present_evr = map { $_ => rpm_evr($dir, $_) } @names;
my %expected = map { $_ => $req{$_} } @names;
my @problems = verify_repo_packages(\%expected, \%present, \%present_evr, \&rpm_vercmp_segment);
if ($tgt eq 'openeuler-24.03-ppc64le') {
eval { $native = load_inputs($repo_root, \%req); 1 }
or push @problems, "Native input catalog: $@";
}
# Signature gate: the IO (gpg) lives here; the decision is the pure verify_repo_signature. The
# pipeline always signs, so a signed repo's repomd MUST be signed by --gpg-key-name. We resolve
@@ -1765,7 +2051,7 @@ sub verify_target_repo {
require_command('rpm');
# (a) RPM-native crypto verification: rpmkeys --checksig against an isolated keyring
# holding only this key verifies every rpm's digests AND that the signature is by the key.
push @problems, verify_rpms_checksig($dir, $gpg_key_name, $gpg_home);
push @problems, verify_rpms_checksig($dir, $gpg_key_name, $gpg_home, $native);
# (b) Explicit signer-id origin check kept alongside: assert each rpm's header signature
# key id is one of this key's ids (primary/subkey).
my $accept = gpg_key_ids($gpg_key_name, $gpg_home);
@@ -1773,7 +2059,7 @@ sub verify_target_repo {
push @problems, "SIGKEY: cannot list key ids for '$gpg_key_name' to verify per-rpm signatures";
} else {
my @rpm_sigs = map { [ basename($_), rpm_signer_keyid($_) ] }
grep { !/\.src\.rpm$/ } glob("$dir/*.rpm");
grep { !/\.src\.rpm$/ && (!$native || !native_publisher_rpm($native, $_)) } glob("$dir/*.rpm");
push @problems, verify_rpm_signatures(\@rpm_sigs, $accept);
}
}
@@ -1794,6 +2080,13 @@ sub verify_target_repo {
return 1;
}
sub native_publisher_rpm {
my ($plan, $rpm) = @_;
my $id = rpm_identity($rpm);
my $owner = $plan->{outputs}{$id->{name}} // return 0;
return $plan->{nodes}{$owner}{type} eq 'publisher';
}
# derive_target_from_repo_path: map a deployed per-target repo path .../rh<N>/<arch> to its manifest
# target section name alma+epel-<N>-<arch>. Returns undef when the path lacks that rh<N>/<arch> tail,
# so the standalone --verify-repo mode can require an explicit --target instead.
@@ -1802,6 +2095,9 @@ sub derive_target_from_repo_path {
my $tgt;
return $tgt unless defined $dir;
$tgt = "alma+epel-$1-$2" if $dir =~ m{/rh(\d+)/([^/]+)/*$};
if ($dir =~ m{/openeuler((?:20|22|24)\.03(?:sp[1-9][0-9]*)?)/(x86_64|ppc64le)/*$}) {
$tgt = "openeuler-$1-$2";
}
return $tgt;
}
@@ -2150,4 +2446,3 @@ sub slurp_chomp {
chomp $line if defined $line;
return $line // '';
}
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
RvdQJiP2pHXAQpBJduIgGAQsGDCk
=WmUf
-----END PGP PUBLIC KEY BLOCK-----
+88
View File
@@ -171,6 +171,94 @@ perl-Net-DNS=0.80
perl-Net-IP=1.26
perl-Path-Class=0.37
[openeuler-20.03sp4-x86_64]
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
perl-Crypt-SSLeay=0.72
perl-HTML-Form=6.07
perl-HTTP-Async=>= 0.30-3
perl-IO-Stty=>= 0.04-5
perl-Net-HTTPS-NB=>= 0.14-3
perl-Net-Telnet=3.04
python3-scp=0.14.5
xCAT-genesis-base=>= 2:2.18.0
[openeuler-22.03sp4-x86_64]
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
perl-Crypt-SSLeay=0.72
perl-HTTP-Async=>= 0.30-3
perl-IO-Stty=>= 0.04-5
perl-Net-HTTPS-NB=>= 0.14-3
perl-Net-Telnet=3.04
xCAT-genesis-base=>= 2:2.18.0
[openeuler-24.03sp3-x86_64]
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
perl-Crypt-SSLeay=0.72
perl-HTTP-Async=>= 0.30-3
perl-IO-Stty=>= 0.04-5
perl-Net-HTTPS-NB=>= 0.14-3
perl-Net-Telnet=3.04
xCAT-genesis-base=>= 2:2.18.0
[openeuler-24.03sp4-x86_64]
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
perl-Crypt-SSLeay=0.72
perl-HTTP-Async=>= 0.30-3
perl-IO-Stty=>= 0.04-5
perl-Net-HTTPS-NB=>= 0.14-3
perl-Net-Telnet=3.04
xCAT-genesis-base=>= 2:2.18.0
[openeuler-24.03-ppc64le]
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
perl-Crypt-SSLeay=0.72
perl-HTTP-Async=>= 0.30-3
perl-IO-Stty=>= 0.04-5
perl-Net-HTTPS-NB=>= 0.14-3
perl-Net-Telnet=3.04
xCAT-genesis-base=>= 2:2.18.0
ksh=1.0.8
net-snmp=5.9.3
net-snmp-libs=5.9.3
net-snmp-perl=5.9.3
perl-DB_File=1.859
perl-Digest-SHA1=2.13
perl-IO-Tty=1.17
perl-Sys-Virt=4.7.0
perl-CGI=4.57
perl-Crypt-CBC=2.33
perl-Expect=1.35
perl-HTML-Form=6.11
perl-LWP-Protocol-https=6.10
perl-Mail-Sender=0.903
perl-Net-DNS=1.40
perl-DBD-Pg=3.18.0
# [common] is NOT a build target. It describes the SHARED repository the OpenEmbedded Genesis
# release is published into (<repo-dep>/common), which lives beside the per-EL cells and is
# therefore invisible to every [<target>] section above. Without it nothing asserted the published
@@ -0,0 +1,14 @@
--- a/postgresql.spec
+++ b/postgresql.spec
@@ -78,7 +78,10 @@
Patch11: postgresql-datalayout-mismatch-on-s390.patch
Patch16: postgresql-pgcrypto-openssl3-tests.patch
-BuildRequires: gcc clang
+BuildRequires: gcc
+%if %llvmjit
+BuildRequires: clang
+%endif
BuildRequires: perl(ExtUtils::MakeMaker) glibc-devel bison flex gawk
BuildRequires: perl(ExtUtils::Embed), perl-devel
BuildRequires: perl-generators
Binary file not shown.
+9
View File
@@ -7,6 +7,9 @@ use File::Basename qw(dirname);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
use FindBin qw($RealBin);
use lib "$RealBin/..";
use MockBuildUtils qw(restamp_release_line);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
@@ -20,6 +23,7 @@ my $mock_uniqueext = '';
my $result_dir = "$repo_root/build-output/list3/xnba-undi";
my $log_dir = "$repo_root/build-logs/list3/xnba-undi";
my $build_timestamp;
my $release_suffix = '';
GetOptions(
'work-dir=s' => \$work_dir,
@@ -28,6 +32,7 @@ GetOptions(
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'build-timestamp=i' => \$build_timestamp,
'release-suffix=s' => \$release_suffix,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
@@ -133,6 +138,9 @@ install -m 644 binary/xnba.efi %{buildroot}/tftpboot/xcat/xnba.efi
- Packaged pre-built xnba binaries for EL10
SPEC
$simple_spec = join('', map { (restamp_release_line($_, $release_suffix))[0] }
split(/(?<=\n)/, $simple_spec)) if $release_suffix ne '';
open my $fh, '>', "$rpmbuild_top/SPECS/xnba-undi.spec"
or die "Cannot write spec: $!\n";
print $fh $simple_spec;
@@ -174,6 +182,7 @@ Options:
--result-dir PATH Output directory for RPMs
--log-dir PATH Output directory for logs
--build-timestamp EPOCH Unix timestamp for reproducible builds
--release-suffix STR Append a suffix to the generated RPM Release
USAGE
}