2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-09-12 12:36:23 +00:00
Files
xcat-dep/genesis-openembedded/build
T
2026-09-06 10:54:28 -03:00

232 lines
8.1 KiB
Python
Executable File

#!/usr/bin/perl
use strict;
use warnings;
use Carp qw(croak);
use Cwd qw(abs_path);
use English qw(-no_match_vars);
use File::Basename qw(basename dirname);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use FindBin;
use Getopt::Long qw(GetOptions);
use POSIX qw(strftime);
use lib "$FindBin::Bin/../lib";
use XCAT::BuildUtils qw(
capture_command
digest_manifest
read_first_line
relative_files
run_command
write_binary
);
use XCAT::GenesisRelease qw(
architectures
deb_package_name
rpm_package_name
validate_architecture
validate_release
);
my $repo_root = abs_path("$FindBin::Bin/..");
my $xcat_source = "$repo_root/../xcat-core";
my $xcat_ref = '';
my $output_dir = '';
my $work_dir = '';
my $format = 'all';
my $all = 0;
my @requested_architectures;
GetOptions(
'xcat-source=s' => \$xcat_source,
'xcat-ref=s' => \$xcat_ref,
'output-dir=s' => \$output_dir,
'work-dir=s' => \$work_dir,
'format=s' => \$format,
'architecture=s@' => \@requested_architectures,
'all!' => \$all,
) or die usage();
die "Unsupported package format: $format\n"
unless $format eq 'all' || $format eq 'rpm' || $format eq 'deb';
die "Use either --all or --architecture\n" if $all && @requested_architectures;
@requested_architectures = architectures() if $all;
@requested_architectures = ('x86_64') unless @requested_architectures;
my %seen;
@requested_architectures = grep { !$seen{$_}++ } @requested_architectures;
validate_architecture($_) for @requested_architectures;
my %requested = map { $_ => 1 } @requested_architectures;
@requested_architectures = grep { $requested{$_} } architectures();
umask(0022);
$xcat_source = abs_path($xcat_source) or die "Cannot resolve xcat-core source\n";
for my $path (qw(Version xCAT-genesis-builder/oe/build xCAT-genesis-builder/oe/export)) {
die "xcat-core source is missing $path\n" unless -f "$xcat_source/$path";
}
die "xcat-core checkout is not clean\n"
if capture_command('git', '-C', $xcat_source, 'status', '--porcelain') ne '';
if ($requested{s390x}) {
my $architecture_reporter = "$xcat_source/xCAT-genesis-builder/oe/build";
my $probe_work = tempdir('xcat-genesis-capabilities.XXXXXX', TMPDIR => 1, CLEANUP => 1);
my $supported_output;
{
local $ENV{XCAT_GENESIS_WORK_DIR} = $probe_work;
local $ENV{TMPDIR} = $probe_work;
$supported_output = eval {
capture_command($architecture_reporter, '--list-architectures');
};
}
my $report_error = $EVAL_ERROR;
if ($report_error) {
croak "xcat-core source does not report supported Genesis architectures: $report_error";
}
if (!defined($supported_output) || !length $supported_output) {
die "xcat-core source reported no supported Genesis architectures\n";
}
my %supported_architecture = map { $_ => 1 } split m{\s+}xms, $supported_output;
if (!$supported_architecture{s390x}) {
die "xcat-core source does not support Genesis architecture s390x\n";
}
}
my $revision = capture_command('git', '-C', $xcat_source, 'rev-parse', 'HEAD');
die "Invalid xcat-core revision: $revision\n" unless $revision =~ /^[0-9a-f]{40}$/;
if ($xcat_ref ne '') {
die "Invalid xcat-core ref: $xcat_ref\n" unless $xcat_ref =~ /^[A-Za-z0-9][A-Za-z0-9._\/-]*$/;
my $expected = capture_command(
'git', '-C', $xcat_source, 'rev-parse', '--verify', "$xcat_ref^{commit}",
);
die "xcat-core HEAD $revision does not match $xcat_ref ($expected)\n"
unless $revision eq $expected;
}
my $version = read_first_line("$xcat_source/Version");
die "Invalid xCAT version: $version\n" unless $version =~ /^\d+(?:\.\d+){1,3}$/;
my $source_date_epoch = capture_command(
'git', '-C', $xcat_source, 'show', '-s', '--format=%ct', 'HEAD',
);
die "Invalid xcat-core commit time\n" unless $source_date_epoch =~ /^\d+$/;
my $release = strftime('snap%Y%m%d%H%M', gmtime($source_date_epoch));
if ($output_dir eq '') {
$output_dir = "$repo_root/build-output/genesis-openembedded/$version-$release";
}
my $output_parent = dirname($output_dir);
make_path($output_parent) unless -d $output_parent;
$output_parent = abs_path($output_parent) or die "Cannot resolve output parent\n";
$output_dir = "$output_parent/" . basename($output_dir);
die "Output already exists: $output_dir\n" if -e $output_dir || -l $output_dir;
my $work = tempdir('xcat-genesis-release.XXXXXX', TMPDIR => 1, CLEANUP => 1);
my $staging = tempdir('.xcat-genesis-release.XXXXXX', DIR => $output_parent, CLEANUP => 1);
my $oe_work;
if ($work_dir ne '') {
make_path($work_dir) unless -d $work_dir;
$work_dir = abs_path($work_dir) or die "Cannot resolve work directory\n";
$oe_work = "$work_dir/openembedded";
} else {
$oe_work = "$work/openembedded";
}
my $oe_tmp = "$oe_work/build/tmp";
local $ENV{XCAT_GENESIS_WORK_DIR} = $oe_work;
{
local $ENV{TMPDIR} = $oe_tmp;
make_path($oe_tmp);
run_command("$xcat_source/xCAT-genesis-builder/oe/build", @requested_architectures);
}
my $effective_deploy = "$oe_tmp/deploy";
die "Invalid OpenEmbedded deploy directory: $effective_deploy\n"
unless -d $effective_deploy && !-l $effective_deploy;
for my $architecture (@requested_architectures) {
my $export = "$work/exports/$architecture";
make_path(dirname($export));
run_command(
"$xcat_source/xCAT-genesis-builder/oe/export",
$architecture, $effective_deploy, $export,
);
my $packages = "$work/packages/$architecture";
run_command(
"$FindBin::Bin/package",
'--architecture', $architecture,
'--export-dir', $export,
'--output-dir', $packages,
'--version', $version,
'--release', $release,
'--revision', $revision,
'--source-date-epoch', $source_date_epoch,
'--format', $format,
);
_collect_packages($packages, $staging, $architecture);
}
my @formats = $format eq 'all' ? qw(deb rpm) : ($format);
my $manifest_version = $requested{s390x} ? 2 : 1;
write_binary(
"$staging/release.manifest",
"format=xcat-genesis-packages\n"
. "version=$manifest_version\n"
. "xcat_version=$version\n"
. "xcat_release=$release\n"
. "xcat_revision=$revision\n"
. "source_date_epoch=$source_date_epoch\n"
. "architectures=" . join(',', @requested_architectures) . "\n"
. "formats=" . join(',', @formats) . "\n",
);
my @release_files = grep { $_ ne 'SHA256SUMS' } relative_files($staging);
write_binary(
"$staging/SHA256SUMS",
digest_manifest($staging, 'sha256', @release_files),
);
validate_release($staging);
my @verify_args = ('--format', $format);
push(@verify_args, '--complete') if $all;
run_command("$FindBin::Bin/verify-release", @verify_args, $staging);
chmod(0755, $staging) or die "Cannot make release directory readable: $!\n";
rename($staging, $output_dir) or die "Cannot publish $output_dir: $!\n";
print "Built Genesis package release in $output_dir\n";
sub _collect_packages {
my ($source, $destination, $architecture) = @_;
if ($format eq 'all' || $format eq 'rpm') {
my $name = rpm_package_name($architecture);
_collect_one(
"$source/rpm/$name-$version-$release.noarch.rpm",
"$destination/rpm",
);
_collect_one(
"$source/srpm/$name-$version-$release.src.rpm",
"$destination/srpm",
);
}
if ($format eq 'all' || $format eq 'deb') {
my $name = deb_package_name($architecture);
_collect_one(
"$source/deb/${name}_${version}-${release}_all.deb",
"$destination/deb",
);
}
}
sub _collect_one {
my ($source, $directory) = @_;
die "Missing package artifact: $source\n" unless -f $source && !-l $source;
make_path($directory) unless -d $directory;
my $destination = "$directory/" . basename($source);
die "Duplicate package artifact: $destination\n" if -e $destination || -l $destination;
copy($source, $destination) or die "Cannot collect $source: $!\n";
}
sub usage {
return <<'USAGE';
Usage: build [--xcat-source DIR] [--xcat-ref REF] [--output-dir DIR]
[--work-dir DIR]
[--format all|rpm|deb] [--architecture ARCH ... | --all]
USAGE
}