Skip to content

Commit

Permalink
mkosi fixes (openSUSE#985)
Browse files Browse the repository at this point in the history
* mkosi: implement obsbinlnk

Allow to build mkosi images using other mkosi images (systemd-sysext)

* mkosi: implement query() and queryhrdmd5() for image dependencies

* vm-type:qemu use virtio on x86_64

* Fix mkosi recipe detection

* Make mkosi call more readable

* mkosi fixes

This makes baseimage builds with mkosi somehow possible. This not a
proper solution. With mkiso the codepath of kiwimode needs to be
activated really and repos be used instead of .build.binaries.

---------

Co-authored-by: Luca Boccassi <[email protected]>
Co-authored-by: Adrian Schröter <[email protected]>
  • Loading branch information
3 people authored Apr 5, 2024
1 parent cdc4b5b commit 71c0390
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 6 deletions.
2 changes: 2 additions & 0 deletions Build.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,7 @@ sub query {
return Build::Kiwi::queryiso($handle, %opts) if $do_kiwi && $binname =~ /\.iso$/;
return Build::Arch::query($handle, %opts) if $do_arch && $binname =~ /\.pkg\.tar(?:\.gz|\.xz|\.zst)?$/;
return Build::Arch::query($handle, %opts) if $do_arch && $binname =~ /\.arch$/;
return Build::Mkosi::queryiso($handle, %opts) if $do_mkosi && $binname =~ /\.(raw|tar|cpio|qcow2)(?:\.gz|\.xz|\.zstd)?$/;
return undef;
}

Expand All @@ -1392,6 +1393,7 @@ sub queryhdrmd5 {
my ($binname) = @_;
return Build::Rpm::queryhdrmd5(@_) if $do_rpm && $binname =~ /\.d?rpm$/;
return Build::Deb::queryhdrmd5(@_) if $do_deb && $binname =~ /\.deb$/;
return Build::Mkosi::queryhdrmd5(@_) if $do_mkosi && $binname =~ /\.(raw|tar|cpio|qcow2)(?:\.gz|\.xz|\.zstd)?$/;
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.iso$/;
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.raw$/;
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.raw.install$/;
Expand Down
65 changes: 65 additions & 0 deletions Build/Mkosi.pm
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,76 @@ sub parse {
if (length $cfg->val('Content', 'BuildPackages')) {
push(@packages, split /\s+/, $cfg->val('Content', 'BuildPackages'));
}
# XXX: split by comma
if (length $cfg->val('Content', 'BaseTrees')) {
push(@packages, "mkosi:".$cfg->val('Content', 'BaseTrees'));
}

$ret->{'name'} = $fn;
$ret->{'deps'} = \@packages;

return $ret;
}

sub queryiso {
my ($file, %opts) = @_;
my $json_fh;
my $md5 = Digest::MD5->new;

open(my $fh, '<', $file) or die("Error opening $file: $!\n");
$md5->addfile($fh);
close($fh);
# If we also have split verity artifacts, the manifest file is the same as the main image,
# so remove the suffixes to find it
$file =~ s/(\.root|\.usr)//g;
$file = $file . ".manifest.gz";

eval { require JSON; };
*JSON::decode_json = sub {die("JSON::decode_json is not available\n")} unless defined &JSON::decode_json;

eval { require IO::Uncompress::Gunzip; };
*IO::Uncompress::Gunzip::new = sub {die("IO::Uncompress::Gunzip is not available\n")} unless defined &IO::Uncompress::Gunzip::new;

my $json_text = do {
open($json_fh, "<", $file) or die("Error opening $file: $!\n");
$json_fh = IO::Uncompress::Gunzip->new($json_fh) or die("Error opening $file: $IO::Uncompress::Gunzip::GunzipError\n");
local $/;
<$json_fh>
};

my $metadata = JSON::decode_json($json_text);
close $json_fh;

if (!$metadata || !$metadata->{'config'}) {
return {};
}

my $distribution = $metadata->{'config'}->{'distribution'};
my $release = $metadata->{'config'}->{'release'};
my $architecture = $metadata->{'config'}->{'architecture'};
my $name = $metadata->{'config'}->{'name'};
my $version = $metadata->{'config'}->{'version'};
my @provides = ("$distribution:$release");

return {
'provides' => \@provides,
'version' => $version,
'arch' => $architecture,
'name' => $name,
'source' => $name,
'hdrmd5' => $md5->hexdigest(),
};
}

sub queryhdrmd5 {
my ($bin) = @_;

open(my $fh, '<', $bin) or croak("could not open $bin");
my $md5 = Digest::MD5->new;
$md5->addfile($fh);
close($fh);

return $md5->hexdigest();
}

1;
7 changes: 7 additions & 0 deletions PBuild/BuildResult.pm
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ sub integrate_build_result {
PBuild::Util::cp_a($result->{$file}, "$dst/$file");
next;
}
if ($file =~ /(.*)\.manifest(?:\.(?:gz|bz2|xz|zst|zstd))?$/) {
# create an obsbinlnk file from the mkosi manifest
my $prefix = $1;
die unless $result->{$file} =~ /^(.*)\/([^\/]+)$/;
my $obsbinlnk = PBuild::Container::manifest2obsbinlnk($1, $2, $prefix, $p->{'pkg'});
PBuild::Util::store("$dst/$prefix.obsbinlnk", undef, $obsbinlnk) if $obsbinlnk;
}
PBuild::Util::cp($result->{$file}, "$dst/$file");
}
# create new bininfo
Expand Down
62 changes: 62 additions & 0 deletions PBuild/Container.pm
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,70 @@ use PBuild::Verify;
eval { require JSON::XS };
*JSON::XS::decode_json = sub {die("JSON::XS is not available\n")} unless defined &JSON::XS::decode_json;

eval { require IO::Uncompress::Gunzip; };
*IO::Uncompress::Gunzip::new = sub {die("IO::Uncompress::Gunzip is not available\n")} unless defined &IO::Uncompress::Gunzip::new;

use strict;

sub manifest2obsbinlnk {
my ($dir, $file, $prefix, $packid) = @_;
my $json_fh;
my $md5 = Digest::MD5->new;
my $image;
my $json_text = do {
unless (open($json_fh, "<", "$dir/$file")) {
warn("Error opening $dir/$file: $!\n");
return {};
}
if ($file =~ /\.gz$/) {
$json_fh = IO::Uncompress::Gunzip->new($json_fh) or die("Error opening $dir/$file: $IO::Uncompress::Gunzip::GunzipError\n");
}
local $/;
<$json_fh>
};

my $metadata = JSON::XS::decode_json($json_text);
if (!$metadata || !$metadata->{'config'}) {
return {};
}

for my $ext ("", ".raw", ".gz", ".xz", ".zst", ".zstd") {
my $fn = "$dir/$prefix$ext";
if (-e $fn) {
if (-l $fn) {
$prefix = readlink($fn);
}
open(my $fh, '<', "$dir/$prefix$ext") or die("Error opening $dir/$prefix$ext: $!\n");
$md5->addfile($fh);
close($fh);
$image = $prefix . $ext;
last;
}
}
if (!$image) {
return {};
}

my $distribution = $metadata->{'config'}->{'distribution'};
my $release = $metadata->{'config'}->{'release'};
my $architecture = $metadata->{'config'}->{'architecture'};
my $name = $metadata->{'config'}->{'name'};
my $version = $metadata->{'config'}->{'version'} || '0';
# Note: release here is not the RPM release, but the distribution release (eg: Debian 10)
my @provides = ("$distribution:$release", "mkosi:$name = $version", "mkosi:$packid = $version");

return {
'provides' => \@provides,
'source' => $packid,
'name' => "mkosi:$name",
'version' => $version,
'release' => '0',
'arch' => $architecture,
'hdrmd5' => $md5->hexdigest(),
'lnk' => $image,
};
}

sub containerinfo2nevra {
my ($d) = @_;
my $lnk = {};
Expand Down
6 changes: 4 additions & 2 deletions PBuild/Job.pm
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ sub createjob {
my $kiwimode = $p->{'buildtype'} eq 'kiwi' || $p->{'buildtype'} eq 'docker' || $p->{'buildtype'} eq 'fissile' || $p->{'buildtype'} eq 'productcompose' ? $p->{'buildtype'} : undef;
if ($kiwimode) {
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, @$sysdeps);
} elsif ($p->{'buildtype'} eq 'mkosi') {
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, grep {!/^mkosi:/} @$bdeps, @$sysdeps);
} else {
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, @$bdeps, @$sysdeps);
}
Expand Down Expand Up @@ -262,7 +264,7 @@ sub createjob {
my $copy_sources_asis;
# for kiwi/docker we need to copy the sources to $buildroot/.build-srcdir
# so that we can set up the "repos" and "containers" directories
if ($kiwimode || $p->{'asset_files'} || grep {/\/$/} keys %{$p->{'files'} || {}}) {
if ($kiwimode || $p->{'buildtype'} eq 'mkosi' || $p->{'asset_files'} || grep {/\/$/} keys %{$p->{'files'} || {}}) {
$srcdir = "$buildroot/.build-srcdir";
copy_sources($p, $srcdir);
$ctx->{'assetmgr'}->copy_assets($p, $srcdir) if $p->{'asset_files'};
Expand Down Expand Up @@ -340,7 +342,7 @@ sub createjob {
push @args, "--rpm-recipe-in-subdir" if $p->{'recipe'} =~ /^(?:package|dist)\/.*\.spec$/;
push @args, "$srcdir/$p->{'recipe'}";

if ($kiwimode) {
if ($kiwimode || $p->{'buildtype'} eq 'mkosi') {
# now setup the repos/containers directories
$ctx->{'repomgr'}->copyimagebinaries($ctx->dep2bins(@$bdeps), $srcdir);
# and tell kiwi how to use them
Expand Down
2 changes: 1 addition & 1 deletion PBuild/Recipe.pm
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ sub find_recipe {
}
}
if (1) {
@files = grep {/mkosi\.$/} keys %files;
@files = grep {/^mkosi\./} keys %files;
return $files{$files[0]} if @files == 1;
if (@files > 1) {
@files = sort @files;
Expand Down
2 changes: 2 additions & 0 deletions PBuild/RepoMgr.pm
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ sub copyimagebinaries {
$to =~ s/[\/:]/_/g;
PBuild::Verify::verify_filename($to);
$to = "$dstdir/containers/$to";
} elsif ($q->{'name'} =~ /^mkosi:/) {
$to = "$dstdir/$q->{'lnk'}";
} else {
die("package $q->{'name'} is not available\n") unless $q->{'filename'};
PBuild::Verify::verify_filename($q->{'filename'});
Expand Down
22 changes: 19 additions & 3 deletions build-recipe-mkosi
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,23 @@ recipe_build_mkosi() {
if [ -n "$RELEASE" ]; then
image_version="--image-version=${RELEASE}"
fi
chroot "$BUILD_ROOT" sh -c \
"cd $TOPDIR/SOURCES && mkosi --default $RECIPEFILE $RELEASE_ARG $image_version --nspawn-keep-unit --output-dir $TOPDIR/OTHER --checksum --repository-key-check=no --with-network=never --local-mirror file:///.build.binaries/ --cache /.build.binaries/ build" \
|| cleanup_and_exit 1
set -- mkosi \
--directory "$TOPDIR/SOURCES" \
--default \
"$RECIPEFILE" \
$RELEASE_ARG \
$image_version \
--nspawn-keep-unit \
--output-dir "$TOPDIR/OTHER" \
--checksum \
--repository-key-check=no \
--with-network=never \
--local-mirror file:///.build.binaries/ \
--cache /.build.binaries/ \
build

echo "running $*"
chroot "$BUILD_ROOT" "$@" || cleanup_and_exit 1

# move the output files from the subdirectory, as only files in the OTHER/ directory
# are published, but they get deposited in OTHER/$DIST~$RELEASE/
Expand Down Expand Up @@ -130,3 +144,5 @@ recipe_resultdirs_mkosi() {
recipe_cleanup_mkosi() {
:
}

# vim: syntax=sh

0 comments on commit 71c0390

Please sign in to comment.